💡 자료구조

문자열 예제

ji-hyun 2021. 6. 18. 21:48

예제1

 

 

 

#include<stdio.h>

int main() {
	char buffer[40];

	while (1) {
		printf("$ ");
		scanf("%s", buffer);
		printf("%s: %d\n", buffer, strlen(buffer));
	}
	return 0;
}

 

이 코드의 문제점은 scanf("%s", buffer) 부분에서 발생하는데,

scanf("%s", ...) 는 공백을 기준으로 다른 단어로 인식한다.

 

그래서 gets() 라는 함수를 떠올려볼 수 있으나 gets() 함수는 안전하지 않다.

안전하지 않다는 것이 무슨 의미냐하면 buffer 길이를 40으로 제한했음에도 불구하고 40을 넘는 길이의 문자열을 입력했을 때, 그대로 실행이 되면서 40이 넘는 길이를 카운트해주기 때문이다.

 

 

-> gets() 함수는 만약 정해진 사이즈 이상의 문자열을 입력할 때, 메모리 침범이 일어나고 그곳에 중요한 데이터가 있었다면 모두 사라질 수 있다.

 

 

 

그럼 fgets() 함수를 생각해 볼 수 있다.

fgets( 매개변수, 문자열길이, stdin은 표준 입력 즉, 키보드를 의미 )

 

 

#include<stdio.h>
#include<string.h>
#define BUFFER_SIZE 40

int main() {
	char buffer[BUFFER_SIZE];

	while (1) {
		printf("$ ");
		fgets(buffer, BUFFER_SIZE, stdin);
		//buffer[strlen(buffer)-1]='\0';
		printf("%s: %d\n", buffer, strlen(buffer));
	}
	return 0;
}

 

그러나 fgets() 함수를 이용하여 이렇게 코드문을 작성해줬을 경우

출력 결과가 예상한대로 나오지는 않는다.. (첫줄은 입력값이며, 두번째와 세번째줄은 출력값이다)

fgets() 함수는 공백 뿐 아니라 엔터값까지도 카운트 하기 때문이다(엔터값까지 19이다) 따라서 주석으로 처리한 부분까지 작성을 해주어야 원하는 결과가 나올 수 있다.

 

// (엔터값이 들어있을 위치를 널문자로 바꿔버리는 기법)

 

 

-> 그러나 이 역시도 fgets 함수는 길이가 40이 넘는 문자열을 입력하면 출력 결과가 원하는 대로 나오지 않는다. 

40까지 출력하고 나머지 뒷 문자열도 따로따로 세어서 나온다. 그래서 많은 개발자들이 이런 여러가지 제약들이 있는 string 함수들을 쓰는 것이 아니라 임의의 함수를 만들어서 쓰기도 한다. 그 함수는 밑에 있는 코드문과 같다.

 

 

 

 

 

 

#include<stdio.h>
#include<string.h>
#define BUFFER_SIZE 3

int main() {
	char buffer[BUFFER_SIZE];

	while (1) {
		printf("$ ");
		int len = read_line(buffer, BUFFER_SIZE);
		printf("%s: %d\n", buffer, len);
	}
	return 0;
}

int read_line(char str[], int limit) {
	int ch, i = 0;

	while ((ch = getchar()) != '\n')  // 엔터 만나기 전까지 반복한다
		if (i < limit)   
			str[i++] = ch;
	
	str[i] = '\0';  
	return i;
}

 

참고로, getchar 함수는 한 단어씩 입력 받는 함수이다. 쉽게 이해하기 위해서 BUFFER_SIZE 는 3으로 제한하였다. 그리고 밑에 실행결과를 같이 보자.

 

 

실행결과

 

 

 

 

getchar 함수 보충 설명

-> 정확히 말하자면, unsigned char 로 받은 문자를 int 로 변환해서 리턴한다. 오류 발생시에 EOF 를 리턴한다.

 

인자

없음

 

리턴값

읽어들인 문자를 int 값으로 리턴한다.

만일 파일 끝에 도달하거나, 읽기 오류가 발생한다면 함수는 EOF 를 리턴하고 이에 대응하는 오류혹은 EOF 표시자가 설정된다. 

 

 

 

 


예제2

 

 

이번 예제는 문장 앞 뒤의 공백은 제거하되, 단어 사이에 있는 공백은 하나의 공백 문자로 대체해서 카운터해야 하는 예제이다.

 

 

 

 

 

Solution

#include<ctype.h>   // white space 문자인지 검사하는 isspace 함수를 제공
#include<stdio.h>
#include<string.h>

int main() {
	char line[80];
	while (1) {
		printf("$ ");
		int length = read_line_with_compression(line, 80);
		printf("%s:%d\n", line, length);
	}
	return 0;
}

int read_line_with_compression(char compressed[], int limit) {
	int ch, i = 0;
	while ((ch = getchar()) != '\n') {
		if (i < limit - 1 && (!isspace(ch) || i > 0 && !isspace(compressed[i - 1])))
			compressed[i++] = ch;
	}
	if (i > 0 && isspace(compressed[i - 1]))   // 마지막 문자가 공백이면
		i--;
	compressed[i] = '\0';
	return i;
}

 

① while문의 조건식은 줄바꿈의 문자를 만나기 전까지 반복해라는 의미이다.

② if 문의 조건식은 문자열 길이가 limit - 1 보다 작으면서(&&), 공백이 아닌 문자거나(||) 혹은 문자열 i - 1 번째가 공백이 아닐때 compressed[i] 에 ch를 저장한다.

③ while 문이 끝나고 if 문으로 마지막 문자가 공백일 경우 없애준다.

④ 마지막에 문자열의 끝을 알리는 '\0' 을 삽입해준다.