2-1, 2-3 수정

do·2022년 3월 21일
0

API

목록 보기
11/42

2-1 주소록

메모리 낭비 안하기..

  • 한글 4자까지 입력 가능하지만 공백도 입력받기 때문에 name[13]보다는 temp가 커야함
  • 여기서 만약 입력받은 문자열이 temp[50]을 넘어간다면??
#include <stdio.h>
#include <string.h>

enum { MAX_INFO_NUM=5 };

typedef struct {
	char name[13];
	char phone[14];
	char address[151];
} Info;

void SetInfo(Info* info)
{
	int ch;
	int i = 0;
	int j = 0;
	char temp[200];
 	
    printf("이름: ");
 	getchar();
 	fflush(stdin);
    
    ////////////////////////
    //<--gets로 이름 받는 방법-->
 	gets(temp);
 	for (int i = 0; i < sizeof(temp); i++)
		if (temp[i] != ' '){
 			temp[j] = temp[i];
 			j++;
 		}
	snprintf(info->name, 13, "%s", temp);
 	j=0;
    ////////////////////////
    
    ////////////////////////
	<--getchar로 이름 받는 방법-->
	while ((ch = getchar()) != '\n')
		if (ch != ' ')
			temp[i++] = ch;
	temp[i] = '\0';
	snprintf(info->name, 13, "%s", temp);
    ////////////////////////

	printf("전화번호: ");
	fflush(stdin);
	gets(temp);
	snprintf(info->phone, 14, "%s", temp);

	printf("주소: ");
	fflush(stdin);
	gets(temp);
	for (int i=0; i<sizeof(temp)-1; i++)
		if (temp[i]==' ' && temp[i+1]==' ')
			continue;
		else{
			temp[j] = temp[i];
			j++;
		}
	snprintf(info->address, 151, "%s", temp);
}

void GetInfo(Info* info)
{
	puts("-------------------------");
	printf("         ");
	puts(info->name);
	puts("-------------------------");
	printf("전화번호: ");
	puts(info->phone);
	printf("주    소: ");
	puts(info->address);
	puts("-------------------------");
}

int Menu()
{
	int select;
	do {
		puts("1) 주소 입력");
		puts("2) 주소 출력");
		puts("3) 종료");
		printf("select num: ");
		scanf("%d", &select);
	} while(select!=1 && select!=2 && select!=3);
	return select;
}

int main()
{
	Info person[MAX_INFO_NUM];
	int count = 0;

	while (1){
		switch(Menu())
		{
			case 1:
				{
					if (count==5)
						puts("주소를 더이상 등록할 수 없습니다.");
					else{
						count++;
						SetInfo(&person[count-1]);
					}
				}
				break;
 			case 2:
 				{
 					if (!count)
						puts("등록된 주소가 없습니다.");
 					for (int i=0; i<count; i++)
 						GetInfo(&person[i]);
 				}
				break;
			case 3:
				{
					puts("프로그램을 종료합니다.");
					return 0;
				}
				break;
		}
	}
	return 0;
}

2-3 문자열

my_strcpy

  1. my_strcpy 함수는 if문으로 수정했습니다.
  2. my_strcpy 함수에서 dest_buf_size 값과 비교되는 대상 값이 같을 때 temp 값을 dest_buf_size-1로 적용했습니다.
int my_strcpy(char* dest, size_t dest_buf_size, const char* src, size_t src_buf_size)
{
	size_t temp = 0;
	if (strlen(src) < src_buf_size) {
		if (dest_buf_size <= strlen(src))
			temp = dest_buf_size - 1;
		else
			temp = strlen(src);
	}
	else {
		if (dest_buf_size <= src_buf_size)
			temp = dest_buf_size - 1;
		else
			temp = src_buf_size;
	}
	for (int i=0; i<temp; i++)
		dest[i] = src[i];
	dest[temp] = '\0';
	return 0;
}

my_strcat, mystrstr, mystrtok

  1. my_strcat 함수 수정
  2. my_strcat, my_strstr, my_strtok 함수 설명
char* my_strcat(char* str, const char* add)
{
	char* c;
    c = str;

	while (*str!='\0'){
		//*c = *str;	//불필요함
        c++;
        str++;
	}
    
	while (*add!='\0'){
		*c = *add;
		c++;
		add++;
	}

	*c = '\0';
	return c;
}

char* my_strstr(const char* str, const char* find)
{
	char* c = NULL;
    
	if (*find == '\0')					//전달받은 인자의 값이 NULL이면
		return (char*)str;				//str 문자열 그대로 반환함
        
	while (*str != '\0'){				//str 문자 값이 NULL이 되면 반복문 중지
		if (c != NULL && *find == '\0')	//find 문자열을 전부 탐색했으면 반복문 탈출
			break;
		if (c != NULL && *str != *find)	//find가 포함된줄 알다가, 똑같지 않은 상태인거 알고
			c = NULL;					//c를 다시 비워줌
		if (c == NULL && *str == *find)	//c가 비어있는 상태에서 find의 첫번째 값을 찾았다면,
			c = (char*)str;				//find의 첫번째 값의 포인터를 c에 대입함
		if (c != NULL && *str == *find) //위 if문에서 바로 연결되어서, find 포인터 1증가
			find++;						//(find의 두번째 값을 검색하기 시작함)
		str++;							//str 포인터 1증가 (find를 찾지 못하면 계속 str++만 반복함)
	}
    
    if (c != NULL)
		return c;						//c가 NULL이 아니면, c를 리턴함
	else
		return NULL;					//str에 find가 나타나지 않았으니 NULL을 리턴함 
}

char* my_strtok(char* str, const char* delim)
{
	static char* s = NULL;		//str 문자열 계속 저장하기 위해 정적변수 s를 선언함
	char* d = NULL;				//while문 반복을 위해 임시공간 d를 선언함
    
	if (str != NULL)			//처음 전달된 str 문자열 s에 대입함
		s = str;
	else						//구분자를 찾으면 그 구분자를 '\0'로 변환하기 때문에
								//처음에만 문자열 전체를 넣어주고, 그 다음부터 '\0'부터 찾음
		str = s;				//아래 while 반복문에서 s가 가리키는 위치는 잘린문자열+'\0' 그 이후로,
								//정적변수인 s는 함수를 벗어나도 유지됨 - 그대로 str에 대입함
	
	if (*s == '\0')				//더이상 자를 문자열이 없으면 NULL을 리턴함
		return NULL;
        
	while (*s != '\0) {
		d = (char*)delim;		//d에 구분자를 대입함
		while (*d != '\0') {
			if (*s == *d) {		//문자열 중 구분자를 찾으면
				*s = '\0';		//그 구분자를 '\0'로 바꾸어줌
				s++;			//다음 구분될 문자열 찾기 위해 s 포인터 1 증가
				return str;		//'\0'을 만날때까지의 (자른) 문자열을 리턴함
			}
			d++;
			}
		s++;
	}
	return str;	//구분자 없이 남은 마지막 문자열은 위 while문에서 구분자를 찾지 못하기 때문에
				//따로 문자열을 리턴해야함
}

수강신청.c

  1. 수강신청 프로그램에서 CountCheck 함수와 에러 리턴값을 수정했습니다.
  2. 과목명이 담겨있는 const char*를 배열로 수정했습니다.
  3. NameCheck 함수에서 strstr로 과목명을 검색하는건 잘못된 방식이어서 strcmp로 수정했습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum { MIN_ID_NUM = 1, MAX_ID_NUM = 100, MAX_INFO_NUM = 5, MAX_SUBJECT_NUM = 8,
		RANGE_ERROR = -20, COUNT_ERROR = -21, NAME_ERROR = -22};

typedef struct Info {
	int id;
	char subjects[116];
} Info;

const char* Name_Subjects[MAX_SUBJECT_NUM] = {
	"컴퓨터개론", "이산수학", "C언어", "JAVA초급",
	"리눅스구조", "자료구조", "컴파일러", "네트워크개론" };

int IDRangeCheck(Info* info)
{
	if (info->id < MIN_ID_NUM || info->id > MAX_ID_NUM){
		puts("ID의 범위는 1부터 100입니다.");
		return -1;
	}
	return 0;
}

int CountCheck(int* num)
{
	if (*num >= MAX_INFO_NUM){
		puts("수강 신청 정보가 5개를 초과하였습니다.");
		return -1;
	}
	return 0;
}

int NameCheck(char* str)
{
	for (int i = 0; i < MAX_SUBJECT_NUM; i++)
		if (strcmp(Name_Subjects[i], str) == 0)
			return 0;

	puts("존재하지 않은 과목명을 입력하였습니다.");
	return 0;
}

int Menu()
{
	int select;
	do{
		puts("======================");
		puts("1) 수강 신청 정보 입력");
		puts("2) 수강 신청 정보 출력");
		puts("3) 종료");
		printf("Select ==> ");
		scanf("%d", &select);
	} while (select!=1 && select!=2 && select!=3);
	return select;
}

int SetInfo(Info* info)
{
	char copystr[116];
	int j=0;
	copystr[0] = '\0';
	info->subjects[0] = '\0';

	printf("ID: ");
	scanf("%d", &info->id);
	if (IDRangeCheck(info)) //ID범위 체크
		return -1;

	printf("수강 신청 과목: ");
	getchar();
	fflush(stdin);
	gets(copystr);

	for (int i=0; i<sizeof(copystr); i++) //공백 제거
		if (copystr[i]!=' ')
			copystr[j++]=copystr[i];

	char* temp = strtok(copystr, ","); //콤마 분할
    
	while (temp!=NULL){
		if (NameCheck(temp)) //과목명 체크
			return -1;
		strcat(info->subjects, temp); //과목명 이어붙이기
		temp = strtok(NULL, ",");
		if (temp!=NULL)
			strcat(info->subjects, ", "); //마지막 과목 빼고 ", " 덧붙이기
	}
	return 0;
}

void GetInfo(Info* info)
{
	printf("ID: %d, 수강신청 과목: ", info->id);
	puts(info->subjects);
}

int main()
{
	Info data[MAX_INFO_NUM];
	int count = 0;

	while(1)
	{
		switch(Menu())
		{
			case 1:
				{
					if (CountCheck(&count))
						break;
					if (!SetInfo(&data[count]))
						count++;
				}
				break;
			case 2:
				{
					if (!count)
						puts("등록된 정보가 없습니다.");
					for (int i=0; i<count; i++)
						GetInfo(&data[i]);
				}
				break;
			case 3:
				{
					puts("프로그램을 종료합니다.");
					return 0;
				}
		}
	}
	return 0;
}

0개의 댓글