#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 표시자가 설정된다.
이번 예제는 문장 앞 뒤의 공백은 제거하되, 단어 사이에 있는 공백은 하나의 공백 문자로 대체해서 카운터해야 하는 예제이다.
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' 을 삽입해준다.
'💡 자료구조' 카테고리의 다른 글
전화번호부 v2.0 - 파일을 저장하고 로드하기, 알파벳 순으로 정렬 (0) | 2021.06.19 |
---|---|
전화번호부 v1.0 (0) | 2021.06.19 |
시간 복잡도와 빅-오 표기법 (0) | 2021.06.17 |
문자열 (0) | 2021.06.16 |
동적할당 malloc 함수 (0) | 2021.06.16 |