728x90
반응형
기본적인 입출력
- C언어에서는 기억장치에 저장되는 파일을 다루는 것과 마찬가지 방식으로 입출력 장치를 다룬다.
- 따라서 키보드, 모니터와 같은 대부분의 콘솔 장치도 C 프로그램에서는 자동으로 열리는 파일처럼 다뤄진다.
- C언어에서는 stdin 표준 스트림을 통해 입력 장치를 다루며, stdout 표준 스트림을 통해 출력 장치를 다룬다.
스트림(stream)
- C 프로그램은 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림(stream)이라는 것을 통해 다룬다.
- 스트림(stream)이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다. 즉, 스트림은 운영체제에 의해 생성되는 가상의 연결 고리를 의미한다.

- C언어에서 파일과의 연결을 위한 스트림은 사용자가 직접 생성하고 소멸시켜야 한다. 하지만 콘솔 장치에 대한 스트림은 프로그램 실행 시 자동으로 생성되며, 프로그램 종료 시 자동으로 소멸한다.

- C언어에서 기본적으로 제공되는 표준 스트림(standard stream)은 다음과 같다.

EOF(End Of File)
- 운영체제에서 파일의 끝을 탐지하는 방법은 운영체제마다 약간씩 다르다. 하지만 C언어는 운영체제와 상관없이, 파일의 끝에 도달했을 때 언제나 특별한 값을 반환하도록 한다. 그 값을 EOF(End Of File)라고 하며, 실제로 이 값은 -1을 나타낸다.
- 파일뿐만 아니라 키보드를 통한 입력 시에도 입력의 끝을 알려주는 방법이 필요하다. 대부분의 유닉스(UNIX) 시스템에서는 라인의 시작 위치에서 Ctrl+D를 누르면 EOF를 발생시킬 수 있다. 윈도우 명령창에서는 해당 라인의 어디에서든 Ctrl+Z를 누르고 나서 Enter를 누르면 EOF를 발생시킬 수 있다.
- 다음 예제는 사용자가 EOF를 입력할 때까지 계속해서 영문자를 한 문자씩 입력받는 예제다.
#include <stdio.h>
int main(void) {
char ch;
printf("EOF가 입력될 때까지 영문자를 계속 입력받습니다 :\n");
printf("(윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다)\n");
while ((ch = getchar()) != EOF) {
putchar(ch);
}
return 0;
}
// EOF가 입력될 때까지 영문자를 계속 입력받습니다 :
// (윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다)
// a
// a
// b
// b
// -1
// -1
// ^Z
단일 문자 입력 함수
- C언어에서 하나의 문자를 입력할 때에는 getchar() 함수나 fgetc() 함수를 사용한다.
getchar() 함수
- getchar() 함수는 표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수다.
#include <stdio.h>
int getchar(void);
fgetc() 함수
- fgetc() 함수는 getchar() 함수와 마찬가지로 표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수다. 하지만 getchar() 함수와는 달리 문자를 입력받을 스트림을 인수로 전달하여 직접 지정할 수 있다. 따라서 fgetc() 함수는 키보드뿐만 아니라 파일을 통해서도 문자를 입력받을 수 있다.
#include <stdio.h>
int fgetc(FILE *stream);
단일 문자 출력 함수
- C언어에서 하나의 문자를 출력할 때에는 putchar() 함수나 fputc() 함수를 사용한다.
putchar() 함수
- putchar() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수다.
#include <stdio.h>
int putchar(int c);
fputc() 함수
- fputc() 함수는 putchar() 함수와 마찬가지로 표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수다. 하지만 putchar() 함수와는 달리 문자를 출력할 스트림을 인수로 전달하여 직접 지정할 수 있다. 따라서 fputc() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있다.
#include <stdio.h>
int fputc(int c, FILE *stream);
- 다음 예제는 단일 문자 입출력 함수를 사용하여, 'x'문자가 입력될 때까지 계속해서 영문자를 입력받고 출력하는 예제다.
#include <stdio.h>
int main(void) {
char ch;
printf("x가 입력될 때까지 영문자를 계속 입력받습니다 :\n");
while ((ch = getchar()) != 'x') {
putchar(ch);
}
printf("x를 입력하셨습니다.\n");
return 0;
}
// x가 입력될 때까지 영문자를 계속 입력받습니다 :
// c
// c
// d
// d
// x
// x를 입력하셨습니다.
문자열(string)
- C언어에서는 큰따옴표("")를 사용해 표현되는 문자열을 문자열 상수(string constant)라고 한다. 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, 문자열의 내용 또한 변경할 수 없기 때문이다.
- C언어에서 문자열(string)은 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미한다. 따라서 문자형 배열을 선언하면 이 배열이 곧 문자열 변수가 된다.
- '%s'는 문자열을 표현하기 위한 입출력 서식 문자다.
char str01[] = "This is a string."; // 크기를 지정하지 않은 문자열 변수 선언
char str02[7] = "string"; // 크기를 지정한 문자열 변수 선언
printf("이것은 문자열 상수입니다.\n"); // 문자열 상수
printf("문자열 str01에 저장되어 있는 문자열은 \"%s\"입니다.\n", str01);
printf("문자열 str02에 저장되어 있는 문자열은 \"%s\"입니다.\n", str02);
// 이것은 문자열 상수입니다.
// 문자열 str01에 저장되어 있는 문자열은 "This is a string."입니다.
// 문자열 str02에 저장되어 있는 문자열은 "string"입니다.
널(NULL) 문자
- 문자형 배열로 선언된 문자열 변수는 문자열의 끝을 프로그램에 따로 알려주어야 한다. 그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레깃값을 구분할 수 있다. 따라서 C언어에서는 문자열에 속한 데이터가 끝나면, 문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다. 이 문자를 널(NULL) 문자라고 하며, '\0'으로 표시하고 아스키코드값은 0이다.
- 다음 예제는 널 문자를 제외한 문자열의 길이를 계산하여 출력해주는 예제다.
int str_len = 0;
char str[] = "string";
while (str[str_len] != '\0') { // 널 문자가 나올 때까지 길이를 증가함
str_len++;
}
printf("이 문자열의 길이는 %d입니다.\n", str_len);
// 이 문자열의 길이는 6입니다.

문자열 입력 함수
- C언어에서 문자열을 입력할 때에는 fgets() 함수를 사용한다.
fgets() 함수
- fgets() 함수는 키보드뿐만 아니라 파일에서도 문자열을 입력받을 수 있는 함수다.
#include <stdio.h>
char *fgets(char * restrict s, int n, FILE * restrict stream);
- fgets() 함수의 첫 번째 인수는 입력받는 문자열을 저장하기 위해 선언한 배열의 시작 주소를 전달한다. 두 번째 인수로는 입력받을 수 있는 문자열의 최대 길이를 전달하고, 마지막 인수로는 문자열을 입력받을 스트림을 전달한다.
문자열 출력 함수
- C언어에서 문자열을 입력할 때에는 puts()함수나 fputs() 함수를 사용합니다.
puts() 함수
- puts() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자열을 출력하는 함수다. 이 함수는 모니터에 문자열을 출력한 다음에 자동으로 줄을 바꿔준다.
#include <stdio.h>
int puts(const char *s);
- puts() 함수는 인수로 출력할 문자열을 가리키는 포인터를 전달한다.
fputs() 함수
- fputs() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수다. 이 함수는 puts() 함수와는 달리 문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다.
#include <stdio.h>
int fputs(const char * restrict s, FILE * restrict stream);
- fputs() 함수의 첫 번째 인수는 출력할 문자열을 가리키는 포인터를 전달한다. 두 번째 인수로는 문자열을 출력할 스트림을 전달한다.
#include <stdio.h>
int main(void) {
char str[100];
fputs("문자열을 입력해 주세요 :\n", stdout);
fgets(str, sizeof(str), stdin);
puts("입력하신 문자열 : ");
puts(str);
fputs("입력하신 문자열 : ", stdout);
fputs(str, stdout);
return 0;
}
// 문자열을 입력해 주세요 :
// C언어 문자열 입출력
// 입력하신 문자열 :
// C언어 문자열 입출력
// 입력하신 문자열 : C언어 문자열 입출력
- 위의 예제에서 puts() 함수는 문자열을 출력한 후에 자동으로 줄 바꿈을 해주지만 fputs() 함수는 문자열을 출력한 후에 줄 바꿈을 하지 않는다.
문자열 처리 함수
- C언어에서 문자열이란 마지막에 널 문자를 가지는 문자형 배열로 표현되며, 기본 타입에는 포함되지 않는다. 따라서 C 컴파일러가 기본 타입을 위해 제공하는 다양한 연산자를 자유롭게 사용할 수 없다. 이 때문에 C언어는 문자열을 처리하기 위한 다양한 함수를 별도로 제공하고 있다.
strlen() 함수
- strlen() 함수는 인수로 전달된 문자열의 길이를 반환하는 함수다. 이때 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다.
#include <string.h>
size_t strlen(const char *s);
- 다음은 strlen() 함수를 이용하여 문자열의 길이를 구하는 예제다.
char str[] = "C언어";
printf("이 문자열의 길이는 %d입니다.\n", strlen(str));
// 이 문자열의 길이는 7입니다.
// 참고로 utf-8 인코딩 환경에서 한글은 한 문자당 3바이트다.
strcat(), strncat() 함수
- strcat()함수와 strncat() 함수는 하나의 문자열에 다른 문자열을 연결해주는 함수다.
#include <string.h>
char *strcat(char * restrict s1, const char * restrict s2);
- strcat() 함수의 첫 번째 인수로 전달된 문자열은 기준 문자열이 된다.
- 두 번째 인수로 전달된 추가하고자 하는 문자열의 복사본이 기준 문자열 뒤에 추가된다.
- 위의 원형에서 볼 수 있는 restrict 키워드는 포인터의 선언에서만 사용할 수 있는 C99부터 추가된 키워드다. 포인터를 선언할 때 이 키워드를 명시하면, 컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시한다.

- 이때 기준 문자열이 저장된 배열의 공간이 충분하지 않으면, 배열을 채우고 남은 문자들이 배열 외부로 흘러넘칠 수 있다. 이 현상을 배열 오버플로우(overflow)라고 한다.
- 배열 오버플로우 현상을 방지하기 위해서는 strcat() 함수 대신에 strncat() 함수를 사용하는 것이 좋다.
- strncat() 함수는 strcat() 함수와 하는 일은 같지만, 세 번째 인수로 추가할 문자열의 최대 길이를 지정할 수 있다. 이 함수는 널 문자를 만나거나, 추가하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 추가를 계속한다.
#include <string.h>
char *strncat(char * restrict s1, const char * restrict s2, size_t n);
- 아래 예제에서는 우선 널 문자를 포함한 총 14바이트 크기의 문자열을 19바이트 크기의 배열에 저장하고 그 문자열에 정확히 5바이트 크기의 문자열을 추가하는 예제다.
- 이때 strncat() 함수가 아닌 strcat() 함수를 사용해도 괜찮지만, 만약 5바이트 이상의 문자열을 추가하려고 한다면 배열 오버플로우가 발생할 것이다.
char str01[20] = "C language is "; // 널 문자를 포함하여 15문자
char str02[] = "Cool! and funny!";
//strcat(str01, str02); // 이 부분의 주석 처리를 삭제한 후 실행시키면 배열 오버플로우우가 발생함
strncat(str01, str02, 5); // 이렇게 최대 허용치를 설정해 놓으면 배열 오버플로우우에 대해서는 안전해짐
puts(str01);
// C language is Cool!
strcpy(), strncpy() 함수
- strcpy() 함수와 strncpy() 함수는 문자열을 복사하는 함수다
#include <string.h>
char *strcpy(char * restrict s1, const char * restrict s2);
- strcpy() 함수는 첫 번째 인수로 전달된 배열에, 두 번째 인수로 전달된 문자열을 복사한다. 하지만 이때 첫 번째 인수로 전달된 배열의 크기가 복사할 문자열의 길이보다 작으면, 배열 오버플로우가 발생한다. 배열 오버플로우 현상을 방지하기 위해서는 strcpy() 함수 대신에 strncpy() 함수를 사용하는 것이 좋다.

- strncpy() 함수는 strcpy() 함수와 하는 일은 같지만, 세 번째 인수로 복사할 문자열의 최대 길이를 지정할 수 있습다. 이 함수는 널 문자를 만나거나, 복사하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 복사를 계속한다.
#include <string.h>
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
- 다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 복사하는 예제다. 이렇게 복사한 문자열의 마지막에는 반드시 널 문자를 삽입해 주어야만 C 프로그램이 제대로 문자열로 인식할 수 있다.
char str01[20] = "C is Cool!";
char str02[11];
// str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임
strncpy(str02, str01, sizeof(str02)-1);
str02[sizeof(str02)-1] = '\0'; // 이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음
puts(str02);
// C is Cool!
- 다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 수정하는 예제다. strncpy() 함수의 첫 번째 인수에 배열 이름을 이용한 포인터 연산을 사용하여 수정을 시작할 지점을 지정할 수 있다.
char str[20] = "C is cool!";
strncpy(str+5, "nice", 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함
puts(str);
// C is nice!
strcmp(), strncmp() 함수
- strcmp() 함수와 strncmp() 함수는 문자열의 내용을 비교하는 함수다.
#include <string.h>
int strcmp(const char *s1, const char *s2);
- strcmp() 함수는 인수로 두 개의 문자열 포인터를 전달받아, 해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. 두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, 문자열의 맨 앞에서부터 순서대로 비교된다.
- strcmp() 함수의 상황별 반환값은 다음과 같다.

- strncmp() 함수는 strcmp() 함수와 하는 일은 같지만, 세 번째 인수로 비교할 문자의 개수를 지정할 수 있다. 이 함수는 일치하지 않는 문자를 만나거나, 세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다.
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
- 다음 예제는 strcmp() 함수를 이용하여 두 문자열을 비교하는 예제다.
- strcmp() 함수는 문자열을 비교하는 함수이므로, 문자를 비교할 때에는 관계연산자 '=='를 사용해야 한다.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[20];
char ch;
while (1) {
puts("미국의 수도를 입력하세요 :");
scanf("%s", str);
if (strcmp(str, "워싱턴") == 0 || strcmp(str, "washington") == 0) { // 문자열의 비교
puts("정답입니다!");
break;
}
else
puts("아쉽네요~");
fflush(stdin);
puts("\n이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!");
puts("계속 도전하고자 하시면 Enter를 눌러주세요!");
scanf("%c", &ch);
if (ch == 'q') { // 문자의 비교
break;
}
fflush(stdin);
}
return 0;
}
// 미국의 수도를 입력하세요 :
// 뉴욕
// 아쉽네요~
// 이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!
// 계속 도전하고자 하시면 Enter를 눌러주세요!
// 미국의 수도를 입력하세요 :
// 워싱턴
// 정답입니다!
- atoi(), atol(), atoll(), atof() 함수
- 이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수다.
#include <stdlib.h>
int atoi(const char *nptr); // int형 정수로 변환함.
long int atol(const char *nptr); // long형 정수로 변환함.
long long int atoll(const char *nptr); // long long형 정수로 변환함.
double atof(const char *nptr); // double형 실수로 변환함.
- 다음 예제는 숫자로 이루어진 문자열을 숫자로 변환하여, 곱셈 연산을 수행하는 예제다.
char str01[] = "10";
char str02[] = "20";
printf("문자열을 숫자로 변환해서 곱한 값은 %d입니다.\n", atoi(str01) * atoi(str02));
// 문자열을 숫자로 변환해서 곱한 값은 200입니다.
toupper(), tolower() 함수
- 이 함수들은 인수로 전달된 문자열의 영문자를 모두 대문자나 소문자로 변환시켜주는 함수다.
#include <ctype.h>
int toupper(int c); // 문자열의 모든 영문자를 대문자로 변환함.
int tolower(int c); // 문자열의 모든 영문자를 소문자로 변환함.
- 다음 예제는 문자열 내의 모든 영문자를 대문자로 변환하는 예제다.
int i, str_len;
char str[] = "Hello C World!";
printf("원래 문자열 : %s\n", str);
str_len = strlen(str);
for (i = 0; i < str_len; i++) {
str[i] = toupper(str[i]);
}
printf("바뀐 문자열 : %s\n", str);
// 원래 문자열 : Hello C World!
// 바뀐 문자열 : HELLO C WORLD!
Reference
728x90
반응형
'Language > C' 카테고리의 다른 글
| [C] C언어 입력과 출력 - 콘솔, 파일, 함수 (1) | 2026.06.08 |
|---|---|
| [C] C언어 구조체 - 개념, 포인터, 활용, 공용체와 열거체 (0) | 2026.06.08 |
| [C] C언어 메모리 관리 - 구조, 스택 프레임, 동적 할당 (0) | 2026.06.07 |
| [C] C언어 포인터와 배열 - 관계, 포인터 배열과 배열 포인터 (0) | 2026.06.07 |
| [C] C언어 포인터 - 개념, 연산, 인수 전달 방법, 이중/void/함수/Null 포인터 (0) | 2026.06.07 |