본문 바로가기

Information Technology/C

[C언어] 문자열(2)

#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 20

int main()
{
	char buffer[40];

	while (1)
	{
		printf("\ ");
		fgets(buffer, BUFFER_SIZE, stdin); 
        	// (저장 버퍼, 버퍼의 크기, 버퍼가 데이터를 가져올 파일 포인터). 표준 입력 파일 = stdin
		// BUFFER_SIZE를 이용하기 때문에 허용된 크기만큼만 데이터를 읽어서 저장
		printf("%s:%d\n", buffer, _mbstrlen(buffer));
	}

	return 0;
}

scanf는 입력받은 값 중 공백(' ') 표시 전까지만 입력을 받기 때문에 띄어쓰기를 포함한 문자열을 저장하기 적합하지 않습니다.

이를 보완하는 것이 fgets 함수입니다. fgets 함수는 매개변수를 3개 받는데,

1. 입력 받은 값을 저장할 버퍼

2. 값을 저장할 버퍼의 크기

3. 그리고 버퍼가 데이터를 가져올 파일 포인터 혹은 스트림

이 순서대로 매개변수를 입력합니다. 파일에서 데이터를 가져올 땐 사전에 지정한 파일 스트림에서 허용된 버퍼 크기만큼 데이터를 가져와 버퍼에 저장하고, 콘솔에서 데이터를 직접 입력할 땐 표준 입력 스트림인 stdin을 파일 포인터로 지정하여 콘솔에서 데이터를 입력받고, 이 값을 버퍼에 저장합니다.

fgets 함수는 줄 바꿈 문자('\n')'를 만나기 전까지 문자열을 받아들이기 때문에 scanf 같은 입력 스트림과 달리 공백 문자(' ')까지 스트림에 저장할 수 있습니다.

하지만 fgets는 엔터키('\n')까지 버퍼에 저장하기 때문에, stdin을 통해 입력받은 값을 출력해보면 입력한 문자열에 한 칸이 띄어져서 출력이 되는 걸 확인할 수 있습니다.


C언어에는 문자열 입/출력에 대해 다양한 함수들이 존재합니다.하지만 다양한 함수들이 프로그래머의 모든 니즈를 항상 만족시키는 건 아니기 때문에 아예 입출력에 관해 필요한 기능을 직접 만들어 사용하는 것도 또 다른 방법 중 하나입니다.

int readline(char str[], int limit)
{
	int ch, i = 0;	// getchar가 int로 데이터를 반환하기 때문에 ch가 int형 자료형
	while ((ch = getchar()) != '\n')	// getchar: 한 문자씩 읽어냄. 
		if (i < limit-1)	// null 문자를 저장할 마지막 공간을 남겨둠
			str[i++] = ch;
	str[i] = '\0'; // 마지막 인덱스를 null문자로 지정하여 완전한 문자열로 만듬.
	return i;	// 입력 받은 데이터를 저장한 배열의 길이 리턴
}

위와 같이 readline이라는 함수를 만들어 정해진 길이 만큼의 데이터만 저장하는 함수를 만들 수 있습니다.

여기서는 getchar()이라는 함수를 사용했는데, getchar() 함수는 입력받은 데이터를 한 문자씩 읽어냅니다. getchar를 통해 데이터를 입력받는 ch는 char이 아닌 int형 변수인데, 이는 getchar를 통해 입력받은 char이 리턴될 때는 int로 리턴되기 때문이라고 이해하시면 될 것 같습니다.

int main()
{
	char buffer[40];

	while (1)
	{
		printf("$ ");
		int len = readline(buffer, BUFFER_SIZE); // readline 함수의 리턴값을 통해 문자열의 길이 저장
		printf("%s: %d\n", buffer, len);
	}

	return 0;
}

그리고 main함수에서 위와 같이 코드를 정하고 프로그램을 실행시키면

의도한 대로 정해진 BUFFER_SIZE 만큼의 데이터만 입력을 받아 출력하는 걸 볼 수 있습니다.


int read_line_with(char compressed[], int limit)
{
	int ch, i;
	ch = getchar();
	while (ch != '\n')
	{
		if (i < limit && (!isspace(ch) || i > 0 && !isspace(ch)))
			compressed[i] = ch;
	}
	if (i > 0 && compressed[i] == ' ') // 마지막 문자열이 공백이면
		i--;
	compressed[i] = '\0'; // 배열 마지막에 null문자 입력

	return i;
}

이번에는 버퍼와 최대 길이를 매개변수로 받아서, 문자열이 시작되기 전과 끝난 후의 공백은 제거하고, 문자열 중간에 대해서는 공백이 2개 이상이면 오직 1개의 공백만 입력 받는 read_line_with 함수입니다.

이 함수에서는 해당 변수가 공백인지 확인하는 isspace 함수를 사용했습니다. isspace 함수는 <ctype.h> 헤더를 추가해줘야 사용할 수 있습니다.

isspace 함수는 띄어쓰기 외에 탭과 같은 공백을 모두 검사해주기 때문에 공백을 검사하는 데 유용한 함수입니다.

'Information Technology > C' 카테고리의 다른 글

[C언어] 전화번호부 v.4  (0) 2020.01.07
[C언어] 전화번호부 v.3  (0) 2020.01.06
[C언어] 전화번호부 v.2  (0) 2020.01.06
[C언어] 전화번호부 v.1  (0) 2020.01.06
[C언어] 문자열(1)  (0) 2020.01.03