1. 프로젝트 동작
프로젝트는 처음 동작 시, 위 처럼 보여진다.
프로젝트의 동작은 아래와 같다.
1. 전화번호 입력
이름과 전화번호를 받아 저장한다.
2. 전체 정보 출력
지금까지 저장한 모든 정보를 출력한다.
3. 전화번호 검색
이름으로 검색하여 이름에 해당하는 모든 데이터를 출력한다.
4. 전화번호 삭제
이름으로 검색하면 이름에 해당하는 모든 데이터가 출력되고, 그중에 선택하여 삭제할 수 있다.
5. 전화번호 변경
이름으로 검색하면 이름에 해당하는 모든 데이터가 출력되고, 그중에 선택하여 변경할 수 있다.
6. 종료
2. 프로젝트 구조
< 헤더 파일 >
1. common.h - C 라이브러리를 선언한 헤더 파일
2. phoneData.h - 프로젝트에서 사용할 데이터의 선언문이 위치한 헤더 파일
3. phoneFunc.h - 프로젝트에서 사용할 기능적인 부분의 함수가 위치한 헤더 파일
4. screen.h - 출력용 함수가 위치한 헤더 파일
< 소스 파일 >
1. main.c - 사용자가 처음 마주하는 인터페이스의 구조를 가지고 있는 소스 파일
2. phoneFunc.c - main에서 사용하는 숫자 입력마다의 기능적인 부분의 함수를 작성한 소스 파일
3. screenOut.c - 사용자에게 출력해주기 위한 함수를 작성한 소스 파일
3. 헤더 코드
1. common.h
#ifndef __COMMOM_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
기본적으로 사용하는 C 언어 라이브러리를 #include 로 상속 받는다.
2. phoneData.h
/* Name: phoneData.h ver 1.0
* Content: 구조체 phoneData의 선언 및 정의.
*/
#ifndef __PHONEDATA_H__
#define __PHONEDATA_H__
#define NAME_LEN 30
#define PHONE_LEN 30
typedef struct __phoneData
{
char name[NAME_LEN];
char phoneNum[PHONE_LEN];
} phoneData;
#endif
프로젝트에서 사용할 구조체를 짠다.
이 프로젝트에서는 이름과 전화번호 2가지만 사용하므로, 위와 같이 선언한다.
3. phoneFunc.h
/* Name: phoneFunc.h ver 1.1
* Content: 전화번호 컨트롤 함수 선언.
*/
#ifndef __PHONEFUNC_H__
#define __PHONEFUNC_H__
void InputPhoneData(void);
void ShowAllData(void);
void SearchPhoneData(void);
void DeletePhoneData(void);
void ChangePhoneData(void);
void StoreDataToFile(void);
void LoadDataFromFile(void);
#endif
/* end of file */
프로젝트에 전반적인 기능을 함수로 정의한 파일이다.
여기서 혹여 phoneData 구조체를 인자로 받아야하는 함수가 필요할 경우 # include "phoneData.h" 를 선언한다.
4. screenOut.h
/* Name: screenOut.h ver 1.1
* Content: 콘솔 출력을 위한 함수 선언
*/
#ifndef __SCREENOUT_H__
#define __SCREENOUT_H__
#include "phoneData.h"
void ShowMenu(void);
void ShowPhoneInfo(phoneData phone);
void ShowPhoneInfoByPtr(phoneData * pPhone);
#endif
/* end of file */
여기에서는 ShowPhoneInfo 와 ShowPhoneInfoByPtr 이 phoneData 포인터를 사용하기에 "phoneData.h"를 #include 해준다.
4. 소스 코드
1. main.c
#include "common.h"
#include "screenOut.h"
#include "phoneFunc.h"
enum { INPUT = 1, SHOWALL, SEARCH, DELETE, CHANGE, QUIT};
/* 함 수: int main (void)
* 기 능: 사용자 선택 처리.
* 반 환: 정상 종료 시 0.
*
*/
int main(void)
{
int inputMenu = 0;
char ch = 0;
LoadDataFromFile();
while (1)
{
ShowMenu();
printf("선택하세요 : ");
scanf_s("%d", &inputMenu);
ch = getchar();
switch (inputMenu)
{
case INPUT:
InputPhoneData();
break;
case SHOWALL:
ShowAllData();
break;
case SEARCH:
SearchPhoneData();
break;
case DELETE:
DeletePhoneData();
break;
case CHANGE:
ChangePhoneData();
break;
}
if (inputMenu == QUIT)
{
StoreDataToFile();
printf("이용해 주셔서 고마워요~\n");
break;
}
}
return 0;
}
/* end of file */
1. #include
"phoneData.h" 가 포함되지 않은 이유는 구조체가 따로 쓰이지 않기 때문이다.
2. enum
enum { INPUT = 1, SHOWALL, SEARCH, DELETE, CHANGE, QUIT};
구동에서도 봤다시피 1~6까지의 입력을 받아 처리하기에 enum 을 선언해 1부터 각각 해당하는 기능을 작성해준다.
3. main
LoadDataFormFile() 함수가 실행되어, 이전에 실행한 적이 있는 내역을 가져와 적용시킨다.
while 문으로 묶어 계속 반복되도록 설정한다.
showmenu() 함수가 실행되어, 1~6까지의 실행 메뉴를 보여준다.
switch 문으로 각 해당하는 기능의 함수를 실행시킨다.
종료를 실행시킬 경우, StoreDataFromFile() 함수를 실행시켜 지금까지의 내역을 파일에 저장한다.
2. phoneFunc.c
/* Name: phoneFunc.c ver 1.3
* Content: 전화번호 컨트롤 함수.
*/
#include "common.h"
#include "phoneData.h"
#include "screenOut.h"
#define LIST_NUM 100
int numOfData = 0;
// phoneData phoneList[LIST_NUM];
phoneData* phoneList[LIST_NUM];
/* 함 수: void InputPhoneData(void)
* 기 능: 전화번호 관련 데이터 입력 받아서 저장.
* 반 환: void.
*
*/
void InputPhoneData(void)
{
// phoneData data;
phoneData* pData = NULL;
char ch = 0;
if (numOfData >= LIST_NUM)
{
printf("메모리 공간이 부족합니다.\n");
return;
}
pData = (phoneData*)malloc(sizeof(phoneData)); // 새로 추가!
if (pData == NULL)
{
printf("메모리 공간이 부족합니다.\n");
return;
}
printf("이름 입력: ");
scanf_s("%s", pData->name, (unsigned)_countof(pData->name));
ch = getchar();
printf("전화번호 입력: ");
scanf_s("%s", pData->phoneNum, (unsigned)_countof(pData->phoneNum));
ch = getchar();
for (int i = 0; i < numOfData; i++)
{
if (!strcmp(phoneList[i]->name, pData->name)&&!strcmp(phoneList[i]->phoneNum, pData->phoneNum))
{
puts("이미 입력된 데이터 입니다.");
free(pData);
ch = getchar();
return;
}
}
phoneList[numOfData++] = pData;
printf("입력이 완료되었습니다.\n");
ch = getchar();
}
/* 함 수: void ShowAllData(void)
* 기 능: 저장된 데이터 전체 출력.
* 반 환: void.
*
*/
void ShowAllData(void)
{
char ch = 0;
for (int i = 0; i < numOfData; i++)
ShowPhoneInfoByPtr(phoneList[i]);
printf("출력이 완료되었습니다.\n");
ch = getchar();
}
/* 함 수: void SearchPhoneData(void)
* 기 능: 이름을 통한 데이터 검색.
* 반 환: void.
*
*/
void SearchPhoneData(void)
{
char searchName[NAME_LEN] = { 0 };
int searchste = 0;
char ch = 0;
printf("찾는 이름은? : ");
scanf_s("%s", searchName, (unsigned)_countof(searchName));
ch = getchar();
for (int i = 0; i < numOfData; i++)
{
if (!strcmp(phoneList[i]->name, searchName))
{
ShowPhoneInfoByPtr(phoneList[i]);
searchste = 1;
}
}
if (searchste == 0)
{
printf("찾는 이름의 데이터가 존재하지 않습니다.\n");
ch = getchar();
}
else
{
puts("검색이 완료되었습니다.");
}
ch = getchar();
}
/* 함 수: void DeletePhoneData(void)
* 기 능: 이름을 참조하여 데이터 삭제.
* 반 환: void.
*
*/
void DeletePhoneData(void)
{
char delName[NAME_LEN] = { 0 };
char ch = 0;
/* 추가된 기능 */
int idxOfMatchingData[LIST_NUM];
int matchedCount = 0;
int selection = 0;
int delIdx = 0;
printf("찾는 이름은? : ");
scanf_s("%s", delName, (unsigned)_countof(delName));
ch = getchar();
/*
for (int i = 0; i < numOfData; i++)
{
if (strcmp(phoneList[i]->name, delName) == 0)
{
free(phoneList[i]); // 새로 추가!
for (int j = i; j < numOfData - 1; j++)
phoneList[j] = phoneList[j + 1];
numOfData--;
printf("삭제가 완료되었습니다.\n");
ch = getchar();
return;
}
}
printf("찾는 이름의 데이터가 존재하지 않습니다.\n");
ch = getchar();
*/
for (int i = 0; i < numOfData; i++)
{
if (!strcmp(phoneList[i]->name, delName))
{
idxOfMatchingData[matchedCount++] = i;
}
}
if (matchedCount == 0)
{
puts("찾는 이름의 데이터가 존재하지 않습니다");
return;
}
else if (matchedCount==1)
{
delIdx = idxOfMatchingData[0];
}
else
{
for (int i = 0; i < matchedCount; i++)
{
printf("NUM. %d \n", i+1);
ShowPhoneInfoByPtr(phoneList[idxOfMatchingData[i]]);
}
fputs("선택 : " , stdout);
scanf("%d", &selection);
ch = getchar();
delIdx = idxOfMatchingData[selection - 1];
}
free(phoneList[delIdx]);
for (int i = delIdx; i < numOfData - 1; i++)
{
phoneList[i] = phoneList[i + 1];
}
numOfData--;
puts("삭제가 완료되었습니다.");
ch = getchar();
}
/* 함 수: void StoreDataToFile(void)
* 기 능: 모든 데이터 파일에 저장.
* 반 환: void.
*
*/
void StoreDataToFile(void)
{
int i;
FILE* fp = fopen("phoneData.dat", "w");
fwrite(&numOfData, sizeof(int), 1, fp); // 데이터 총 개수.
for (i = 0; i < numOfData; i++)
{
/* 문자열을 구분 짓는 문자 \n의 삽입 중요! */
fprintf(fp, "%s\n%s\n", phoneList[i]->name, phoneList[i]->phoneNum);
free(phoneList[i]);
}
fclose(fp);
}
/* 함 수: void LoadDataFromFile(void)
* 기 능: 모든 데이터 파일로부터 복원.
* 반 환: void.
*
*/
void LoadDataFromFile(void)
{
int i, sLen;
FILE* fp = fopen("phoneData.dat", "r");
if (fp == NULL) // 파일이 존재하지 않는다면.
return;
fread(&numOfData, sizeof(int), 1, fp);
for (i = 0; i < numOfData; i++)
{
phoneList[i] = (phoneData*)malloc(sizeof(phoneData));
fgets(phoneList[i]->name, NAME_LEN, fp);
/* 문자열 구분을 위해 입력된 NULL 문자 삭제 */
sLen = strlen(phoneList[i]->name);
phoneList[i]->name[sLen - 1] = 0;
fgets(phoneList[i]->phoneNum, PHONE_LEN, fp);
/* 문자열 구분을 위해 입력된 NULL 문자 삭제 */
sLen = strlen(phoneList[i]->phoneNum);
phoneList[i]->phoneNum[sLen - 1] = 0;
}
fclose(fp);
}
void ChangePhoneData(void)
{
int idxOfMatchingData[LIST_NUM];
int matchedCount = 0;
int selection = 0;
int chIdx = 0;
char ch = 0;
char chName[NAME_LEN] = { 0 };
char newPhoneNumber[PHONE_LEN];
printf("찾는 이름은? : ");
scanf_s("%s", chName, (unsigned)_countof(chName));
ch = getchar();
for (int i = 0; i < numOfData; i++)
{
if (!strcmp(phoneList[i]->name, chName))
{
idxOfMatchingData[matchedCount++] = i;
}
}
if (matchedCount == 0)
{
puts("찾는 데이터가 존재하지 않습니다.");
return;
}
else if (matchedCount == 1)
{
chIdx = idxOfMatchingData[0];
}
else
{
for (int i = 0; i < matchedCount; i++)
{
printf("NUM %d.\n", i + 1);
ShowPhoneInfoByPtr(phoneList[idxOfMatchingData[i]]);
}
fputs("선택 : ", stdout);
scanf("%d", &selection);
ch = getchar();
chIdx = idxOfMatchingData[selection - 1];
}
fputs("변경할 전화번호는? ", stdout);
gets(newPhoneNumber);
strcpy(phoneList[chIdx]->phoneNum, newPhoneNumber);
puts("변경이 완료되었습니다.");
getchar;
}
void StoreDataToFileInSrtuct(void)
{
int i;
FILE* fp = fopen("phoneDataStruct.dat", "wb");
fwrite(&numOfData, sizeof(int), 1, fp);
for (i = 0; i < numOfData; i++)
{
fwrite(phoneList[i], sizeof(phoneData), 1, fp);
}
fclose(fp);
}
void LoadDataFromFileInStruct(void)
{
int i;
FILE* fp = fopen("phoneDataStruct.dat", "rb");
if (fp == NULL)
return;
fread(&numOfData, sizeof(int), 1, fp);
for (i = 0; i < numOfData; i++)
{
phoneList[i] = (phoneData*)malloc(sizeof(phoneData));
fread(phoneList[i], sizeof(phoneData), 1, fp);
}
fclose(fp);
}
/* end of file */
해당하는 기능마다 알고리즘이 설정되어 있다.
pData = (phoneData*)malloc(sizeof(phoneData)); 는 필요한 만큼의 메모리를 할당하는 역할을 한다.
3. screenOut.c
/* Name: screenOut.c ver 1.2
* Content: 콘솔 출력을 위한 함수 정의
*/
#include "common.h"
#include "phoneData.h"
/* 함 수: void ShowMenu(void)
* 기 능: 선택을 위한 메뉴 출력.
* 반 환: void.
*
*/
void ShowMenu(void)
{
system("cls"); //stdlib.h
printf("━━━━━ 메 뉴 ━━━━━━━ \n");
printf(" 1. 전화번호 입력 \n");
printf(" 2. 전체 정보 출력 \n");
printf(" 3. 전화번호 검색 \n");
printf(" 4. 전화번호 삭제 \n");
printf(" 5. 전화번호 변경 \n");
printf(" 6. 종료 \n");
printf("━━━━━━━━━━━━━━━━ \n");
printf("선택》 ");
}
/* 함 수: void ShowPhoneInfo(phoneData phone)
* 기 능: 이름과 전화번호 정보 출력.
* 반 환: void.
*
*/
void ShowPhoneInfo(phoneData phone)
{
printf("┏━━━━━━━━━━━━━━━━ \n" );
printf("┃ ▶ 이름: %s \n", phone.name );
printf("┃ ▶ 전화번호: %s \n", phone.phoneNum );
printf("┗━━━━━━━━━━━━━━━━ \n\n" );
}
/* 함 수: void ShowPhoneInfoByPtr(phoneData * pPhone)
* 기 능: 이름과 전화번호 정보 출력.
* 반 환: void.
*
*/
void ShowPhoneInfoByPtr(phoneData * pPhone)
{
printf("┏━━━━━━━━━━━━━━━━ \n" );
printf("┃ ▶ 이름: %s \n", pPhone->name );
printf("┃ ▶ 전화번호: %s \n", pPhone->phoneNum );
printf("┗━━━━━━━━━━━━━━━━ \n\n" );
}
/* end of file */
출력에 관한 틀을 만들어주는 함수들이다.
마지막으로 어떤 코드이든 알고리즘 보다 구조를 잘짜는 것이 중요하다.
이해가 안되고 있었던 구조들이 조금씩 이해하기 시작했다.
'개발' 카테고리의 다른 글
C 프로그래밍 파워 업그레이드 (가위바위보 게임) (1) | 2024.09.06 |
---|