본문 바로가기

programming language/C 언어

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

chapter 21 -4

출력 버퍼를 비우는 fflush 함수

 

#include<stdio.h>
int fflush(FILE * stream);

 

위의 함수는 인자로 전달된 스트림의 버퍼를 비우는 기능을 제공한다. 출력버퍼가 비워진다는 것은 출력버퍼에 저장된 데이터가 버퍼를 떠나서 목적지로 이동되는 것을 뜻한다.

 

fflush(stdout); // 표준 출력버퍼를 비워라

 

어떠한 시스템의 어떠한 표준 출력버퍼라 할지라도 버퍼에 저장된 내용이 비워지면서 데이터가 목적지로 이동한다고 한다. 추가적으로 위 함수의 인자로 파일의 스트림정보가 전달되면, 해당 버퍼에 저장되어 있던 데이터들이 버퍼를 떠나서 파일에 기록된다.


 

입력 버퍼의 비워짐

 

#include<stdio.h>

void ClearLineFromBuffer(void)
{
	while (getchar() != '\n');
}

int main(void)
{
	char perId[7];
	char name[10];

	fputs("주민번호 앞 6자리 입력: ", stdout);
	fgets(perId, sizeof(perId), stdin);
	ClearLineFromBuffer();

	fputs("이름 입력: ", stdout);
	fgets(name, sizeof(name), stdin);

	printf("주민번호 : %s\n", perId);
	printf("이름: %s\n", name);
	return 0;
}

 

 

입력 버퍼를 비우기 위한 함수를 정의 한 것이다.

 

void ClearLineFromBuffer(void)
{
	while (getchar() != '\n');
}

 

이 함수는 반환하지 않고, 인자도 전달받지 않는다.  getchar 함수는 키보드로부터 하나의 문자를 입력 받는 함수 이다.

위와 같이 함수를 정의한 이유는 입력버퍼에 저장된 문자들은 읽어 들이면 지워지므로, \n을 만날때 까지 문자를 읽어들이는 함수를 정의한것이다. 당연히 읽어 들인 문자는 저장하지 않는다. 버리는 것이 목적이기 때문이다.

 

ClearLineFromBuffer();

 

위와 같이 fgets함수로 인해 입력버퍼가 채워지고, str에 입력된 문자열의 일부가 저장되고 나머지의 것들이 입력버퍼에 남아 있는 상황이라면, 다음 올바른 입력을 위해 입력 버퍼를 비워줘야 한다. 그래서 위 함수를 호출하여 \n이 읽혀질때 까지 입력버퍼에 저장된 문자들을 지워주도록 해야 한다.

 

 

chpter21-5

문자열 길이를 반환하는 함수: strlen

 

#include<stdio.h>
#include<string.h>

void RemoveBSN(char str[])
{
	int len = strlen(str);
	str[len - 1] = 0;
}

int main(void)
{
	char str[100];
	printf("문자열 입력: ");
	fgets(str, sizeof(str), stdin);
	printf("길이: %d, 내용:%s \n", strlen(str),str);

	RemoveBSN(str);
	printf("길이: %d,내용: %s \n",strlen(str),str);
	return 0;
}

 

fgets 함수호출을 통해 문자열을 입력 받는데, 같이 딸려서 들어오는 \n 문자는 문자열에서 제외시키고 싶다면 위 처럼 

strlen을 이용한 RemoveBSN함수를 정의하여 호출하여 주면 된다.

 

위 정의된 함수의 매개변수(즉 인자)가 char str [ ]인데 이는 char * str과 같은것이고, char * str = str(문자열); 과 같은 꼴이 되는 것이다. 매개변수 str이 문자열 str의 주솟값을 그대로 저장하게 된다.

 

fgets 함수를 통해 다음과 같이 1 2 3 4 엔터 가 입력되었고, 뒤에  NULL 이 붙어있는 상황이라 하면  RemoveBSN함수 로 인해서 엔터 자리에 0을 즉 널문자를 저장해줌으로써 엔터(즉\n)는 문자열에서 사라지게 되는 것이다.

 

 

문자열을 복사하는 함수: strcpy, strncpy

 

#include<stdio.h>
#include<string.h>

int main(void)
{
	char str1[20] = "1234567890";
	char str2[20];
	char str3[5];

	// case1
	strcpy(str2, str1);
	puts(str2);

	//case2
	strncpy(str3, str1, sizeof(str3));
	puts(str3);

	//case3
	strncpy(str3, str1, sizeof(str3) - 1);
	str3[sizeof(str3) - 1] = 0;
	puts(str3);
	return 0;

}

 

strncpy 함수의 잘못된 사용

 

//case2
	strncpy(str3, str1, sizeof(str3));
	puts(str3);

 

위의 출력결과는 5개의 문자가 복사가 되기는 하지만 널문자가 str3의 문자열에 존재하지 않게 된다. 널문자가 존재해야 널문자 이전까지 출력을 하는데, 널문자가 존재하지 않으니 엉뚱한 영역까지 출력이 되는 것을 볼 수 있다.

 

strncpy 함수의 올바른 사용

 

//case3
	strncpy(str3, str1, sizeof(str3) - 1);
	str3[sizeof(str3) - 1] = 0;
	puts(str3);

 

strncpy 함수의 세번쨰 인자로 배열의 실제 길이보다 하나 작은 값을 전달해서 널문자가 삽입될 공간을 남겨두고 복사를 진행해줘야 한다. 그리고 str3[sizeof(str3) - 1] = 0; 의 코드를 통해 배열의 끝에 널문자를 삽입해야 한다. 즉 인덱스 넘버로 4 , 5번째 배열 요소값에 0이 삽입되는 것이다

 

sizeof(str3) 의 이해

 

sizeof 연산자가 사용이 되었는데, 이는 문자열의 길이를 계산하는 것이 아니라 배열의 길이를 계산하는것이다. 

문자열의 길이를 계산할때는 널문자를 포함하지 않고, 문자열 그 자체의 길이만 계산하는 것이라면,

sizeof 연산자는 알다시피 문자열이 아닌 배열에서도(예를 들어 int형) 사용이 되기 때문에 널문자를 고려하지 않고 배열의 길이만을 계산해주는 연산자이다. ( 문자열은 배열의 범위(길이) 안에 널문자가 있는데, 이를 문자열길이 계산 때 처럼 제외 하거나 그러지 않고 범위내에 있으니 당연히 배열의 길이 내에 포함된다는 얘기이다 )

 

int main(void)
{
	char str1[20] = "1234567890";
	printf("%d", sizeof(str1));
	return 0;

}

 

위 코드의 출력결과로 20이 출력되는 것을 볼 수 있는데, 배열의 길이가 char str1 [ 20 ]으로 설정이 되어있기 때문이다.