본문 바로가기

문자열 입출력 함수

1. 문자열 출력 함수

 

다음의 두 가지가 있다.

 

int puts(const char* s);

int fputs(const char* s, FILE* stream);

 

매개변수로 전달된 문자열  s 를 출력한다.

엄밀히 말하면  s 는 char형 포인터 변수지만, 문자열은 문자 배열로 표현되며 배열의 이름은 배열의 시작 주소이므로  s 에 문자열 이름을 전달할 수 있다.

 

호출이 성공하면  puts  함수는 0을,  fputs  함수는 0 이상의 정수를 반환하고,

호출이 실패하면 EOF를 반환한다.

즉 음수가 아닌 값이 반환되었다는 것은 에러가 발생하지 않았다는 뜻.

 

참고로  puts  함수는 문자열을 출력할 때 자동으로 끝에 개행 문자가 삽입되지만  fputs  함수는 그렇지 않다. 또한  fputs  함수는  fputc  함수와 마찬가지로  stream  을 통해 출력할 스트림을 지정할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    puts("자동으로");
    puts("개행이");
    puts("삽입된다\n");
 
    fputs("자동으로 ", stdout);
    fputs("개행이 ", stdout);
    fputs("삽입되지 않는다", stdout);
 
    return 0;
}
cs

 

 

 

 

 

2. 문자열 입력 함수

 

char* gets(char* s);

char* fgets(char* s, int n, FILE* stream);

 

 gets  함수는 키보드로부터 문자열을 입력받아  s 에 저장하고,

 fgets  함수는  stream 에 지정한 스트림을 통해 문자열을 입력받아 n 바이트 만큼만

 s 에 입력한다. 

 

함수 호출 성공 시 입력받은 문자열의 시작주소, 즉  s 의 시작 주소가 반환된다.

함수 호출 실패 또는 파일의 끝에 도달하면 NULL을 반환한다.

 

NULL은  (void*) 0 으로 정의된 상수로, 아무것도 가리키지 않는다는 것을 의미한다.

변수에 아무 값도 없는 것(0을 저장하는 것은 0이라는 값을 저장하는 것)은 불가능하므로, 포인터 변수에는 0으로 아무것도 가리키지 않음을 표시하는 것이다.

 

 fgets  함수의 경우 개행 문자까지 문자열의 일부로 받아들인 후 널 문자를 추가한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
int main()
{
    char str[20];
 
    fgets(str, sizeof(str), stdin);
    puts(str); //개행이 두 번
    puts("Clear");
 
    return 0;
}
cs

 

 gets  함수는 배열의 크기를 넘어서는 문자열을 입력받을 위험이 있기 때문에 현재는 사용하지 않는다. 참고로  gets  함수는 버퍼 오버플로우라는 전통적인 해킹 기법에 대한 대표적인 취약점이므로, 컴파일러가  gets  함수를 허용하더라도 사용하지 않는 게 좋다. 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>
 
int main()
{
    char str[10];
 
    fgets(str, sizeof(str), stdin);
    puts(str);
    
    return 0;
}
 
 
cs

 

 

입력한 것은 10글자인데, 출력된 것은 9글자다. 왜 그럴까?

위 코드에서는  str 의 길이, 그러니까 길이 10의 문자열을 입력받는다. 그런데 이 10이라는 길이에는 널 문자가 포함되어 있다. 따라서 실질적으로 입력되는 것은 전체 문자열의 처음 9바이트인 것이다.

 

 

 

 

3. 문자열 입력 함수의 의의

 

출력 함수의 의의는 문자 입출력 함수의 의의에서 했던 이야기와 같으므로 생략한다.

 

 scanf  함수는 공백과 개행 문자로 입력값을 구분한다. 따라서 공백이 포함된 문자열은 입력할 수 없다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
int main()
{
    char str[20];
    
    scanf("%s", str);
    puts(str);
    
    return 0;
}
 
 
cs

 

 

 

Spianato까지 입력받으려면  scanf  함수를 한 번 더 호출해야 한다.  scanf  함수와 같은 무거운 함수를 한 번 더 호출한다는 것은 그만큼 시간과 메모리 자원이 낭비된다는 것이다.

 

따라서 문자열을 입력받을 때는  fgets  함수를 호출하는 게 바람직하다.

 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main()
{
    char str[20];
    
    fgets(str, sizeof(str), stdin);
    puts(str);
    
    return 0;
}  
cs

 

 

 fgets  함수는 개행을 만날 때까지 읽어들이므로 공백도 문자열의 일부로 간주한다.

'Programming > C' 카테고리의 다른 글

문자열 비교 함수  (0) 2019.05.14
문자열 길이 측정, 복사, 연결 함수  (0) 2019.05.13
문자 입출력 함수  (0) 2019.05.05
스트림  (0) 2019.05.01
void형 포인터  (0) 2019.04.15