본문 바로가기

programming language/C 언어

열혈 ( C ) chapter 21 정리노트 3

chapter21 - 3

문자열 입력 함수: gets, fgets

#include<stdio.h>
char * gets(char * s);
char * fgets(char * s,int n,FILE * stream);

gets함수를 사용하면 문장 구성은 간단하지만, 미리 마련해 놓은 배열을 넘어서는 길이의 문자열이 입력되면, 할당받지 않은 메모리 공간을 침범하여 실행 중 오류가 발생한다는 단점이 있다.

그래서 가급적으로 fgets함수를 호출하는 것이 좋다고 한다.

 

<예시>

int main(void)
{
  char str[7];
  fgets(str,sizeof(str),stdin);
   ......................
}

위 코드가 의미하는 바는 stdin으로 부터 문자열을 입력받아서 배열 str에 저장하되, sizeof(str)의 길이만큼만 저장하라! 는 것이다. 사용자가 "123456789"와 같은 문자열을 입력했다면, sizeof(str)의 반환 값인 7 보다 하나가 작은 6에 해당하는 길이의 문자열만 읽어서 str에 저장하게 된다. 즉 str에 저장되는 문자열은 "123456" 이 된다.

 

왜 7이 아닌 6의 길이만큼만 저장이 될까? 

바로 NULL문자의 저장을 위해서이다. 문자열을 입력 받으면 문자열의 끝에 자동으로 널 문자가 추가되기 때문에, 하나가 작은 길이의 문자열이 저장이 되는 것이다.

 

 

<fgets 함수 예시>

#include<stdio.h>
int main(void)
{
	char str[7];
	int i;

	for (i = 0; i < 3; i++)
	{
		fgets(str, sizeof(str), stdin);
		printf("Read %d: %s \n", i + 1, str);
	}
	return 0;
}

사용자가 문자열 "12345678901234567890"을 입력한다 할 때, 입력된 문자열의 길이가 배열의 길이를 넘어선다. 

순서대로 123456(\n) 789012(\n) 345678(\n)와 같이 길이가 6인 문자열들이 출력이 된다. 딱 한번 입력했지만 fgets함수는 3번 호출이 되었다. 물론 3번 호출이 되었음에도 사용자가 입력한 문자열을 모두 읽어드리지는 못하였다. 위의 경우에는 배열의 길이를 늘리거나 fgets를 4번 호출하면 된다.

 

만약, "12345612345612345"의 문자열을 입력하면, fgets함수는 엔터키를 만날때 까지 문자열을 읽어 들이는데,

읽어 들인다는 의미를 문자열을 모두 출력한다 라는 의미로는 받아들이지 말아야 한다. 사용자가 처음 문자열을 입력 할때, 엔터키를 침으로써 입력을 끝내는데, fgets함수가 엔터키를 만날 때까지 문자열을 받아들인다라고 해석하면 이해하기가 쉬울 것 같다.

 

위 입력에 대한 실행결과는 어떨까?  <엔터키도 문자열의 일부>

마지막 Read 3: 12345 출력 이후에 개행이 두번 이루어졌다. 그 이유는 fgets 함수는 \n을 만날 때까지 문자열을 읽어 들이는데,  \n을 제외시키거나 버리지 않고 문자열의 일부로 받아들인다. 즉, 우리가 입력한 엔터 키의 정보까지도 문자열의 일부로 저장된다는 얘기이다.

문자열의 일부로 저장된 \n에 의해 한 번, printf 함수 호출문에 삽입된 \n에 의해서 또 한 번 개행이 이루어졌다.

 

 

<참고> 

fgets함수는 \n을 만날 때까지 문자열을 읽어 들이기 때문에 문자열 중간에 삽입된 공백 문자도 문자열의 일부로 읽어 들인다.

scanf 함수를 통해서는 공백을 포함하는 형태의 문자열을 입력받을 수 없다.