Language/자료구조

[3] C review < 문자열 응용>

Return 2021. 11. 16. 11:42

문제 1.

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

int main(void) {

	char buffer[40];

	while (1) {
		printf("$ ");
		//scanf("%s", buffer); // scanf는 공백 기준으로 나누므로 우리가 원하는 게 아니다.
		fgets(buffer,10,stdin); // gets는 라인별로 입력받는다. but 코드가 안정하지 않다. 
		printf("%s:%d\n", buffer, strlen(buffer));
	}

	return 0;
}

=============================
$ adfdfas
adfdfas
:8

위의 코드의 출력값을 보면 adfdfas : 8이 위 아래로 띄어쓰기 되어 있는데 이는 우리가 원하는것이 아니다. 이러한 현상이 발생하는 이유는 fgets 함수는 우리가 adfdfas를 입력하고 엔터를 눌를때 그 엔터까지 buffer에 저장하기 때문입니다. 즉, 줄바꿈 문자까지 포함해버리는 문제가 발생합니다. (gets함수는 그렇지 않습니다.)

 

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

int main(void) {

	char buffer[40];

	while (1) {
		printf("$ ");
		//scanf("%s", buffer); // scanf는 공백 기준으로 나누므로 우리가 원하는 게 아니다.
		fgets(buffer,10,stdin); // gets는 라인별로 입력받는다. but 코드가 안정하지 않다. 
		buffer[strlen(buffer)-1] = '\0';
		printf("%s:%d\n", buffer, strlen(buffer));
	}

	return 0;
}

buffer의 마지막을 제외해주면 우리가 원하는 값을 얻을 수 있습니다. 하지만 이도 우리가 원하는 값을 완벽히 도출하지는 않습니다. 만약 입력값이 buffer길이를 초과할때 buffer보다 초과된 문자열은 무시하고 싶지만 이는 그렇게 되지 않습니다. 

 

함수를 만들어 우리가 원하는 값이 도출되도록 합니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int read_line(char str[], int limit);

int main(void) {

	char buffer[40];

	while (1) {
		printf("$ ");
		//scanf("%s", buffer); // scanf는 공백 기준으로 나누므로 우리가 원하는 게 아니다.
		// fgets(buffer,10,stdin); // gets는 라인별로 입력받는다. but 코드가 안정하지 않다. 
		//buffer[strlen(buffer)-1] = '\0';
		read_line(buffer, 40);
		printf("%s:%d\n", buffer, strlen(buffer));
	}

	return 0;
}

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

	while ((ch = getchar()) != '\n') // 한글자를 읽어 ch로 하자 
		if (i < limit-1)
			str[i++] = ch; // str[i]에 ch 저장하고 i를 1 증가 시킨다.

	str[i] = '\0';
	return i;

}

 

문제2.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int read_line_with_compression(char compressed[], int limit);

int main(void) {

	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 ((ch = getchar()) != '\n')

 이 조건은 getchar()로 한글자씩 읽어서 ch에 저장하고 줄바꿈 문자인 \n를 만나기 전까지 즉 한라인을 읽어 들이는 조건입니다. 

 

- if (i < limit - 1 && (!isspace(ch) || i > 0 && !isspace(compressed[i - 1])))

  i가0보다 크면서 새로만든compressed[i-1]칸이 공백이 아니거나, 현재ch가 공백이 아닐때,

 동시에 compressed배열의 index를 가리키는 i가 배열의 크기를 초과하지 않을때, compressed배열에 ch를 추가하고 i를 1 더합니다.

 

이조건을 사용하면 문자 시작 전 공백과 문자와 문자사이의 불필요한 공백을 없앨 수 있습니다. 하지만 아직 문제가 남아 있습니다. 문자가 끝난 후 공백에서 발생하는데, 마지막 줄바꿈 문자'\n'에 다다를때, 우리눈에는 공백이지만 컴퓨터에서는 공백으로 인식하지 않아 맨 마지막에 불필요한 공백이 하나 더 생깁니다. 이를 해결하기 위해 다음 조건을 사용합니다. 

if (i > 0 && isspace(compressed[i - 1]))

 이 조건을 사용해 해결하는데, compressed배열에서 특정 인덱스를 가리키는i 바로 앞 칸이 공백이면 불필요한 공백이 생긴 것이므로, i를 하나 줄여줘 최종 i값을 리턴합니다.