1. 문자열과 포인터
문자열의 두 가지 표현 방법
C 언어에서 문자열은 널 문자(\0)로 끝나는 문자 배열입니다. 문자열을 선언하는 방법은 크게 두 가지가 있습니다.
방법 1: 배열 기반 문자열
char str[] = "Hello";
이 방법은 문자 배열을 선언하고 문자열로 초기화합니다. 배열의 크기는 자동으로 6이 됩니다(Hello 5글자 + 널 문자 1개).
| H | e | l | l | o | \0 |
|---|---|---|---|---|---|
| [0] | [1] | [2] | [3] | [4] | [5] |
방법 2: 포인터 기반 문자열
char *str = "Hello";
이 방법은 문자열 상수 “Hello”를 메모리에 저장하고, 그 시작 주소를 포인터 변수 str에 저장합니다.
printf("%s", str); 형태로 문자열을 출력할 수 있습니다.
배열 기반 vs 포인터 기반 차이점
두 방법은 출력은 동일하지만, 수정 가능 여부에서 중요한 차이가 있습니다.
| 구분 | 배열 기반 | 포인터 기반 |
|---|---|---|
| 문자 변경 | ✅ 가능 | ❌ 불가능 |
| 주소 변경 | ❌ 불가능 | ✅ 가능 |
| 특징 | 변수 형태의 문자열 | 상수 형태의 문자열 |
배열 기반 문자열:
char str1[] = "Good";
str1[0] = 'F'; // ✅ 가능: "Food"로 변경
str1 = "New"; // ❌ 불가능: 배열 이름은 상수
포인터 기반 문자열:
char *str2 = "Bad";
str2[0] = 'S'; // ❌ 불가능: 문자열 상수 영역 (실행 시 오류 가능)
str2 = "New Bad"; // ✅ 가능: 포인터가 다른 문자열을 가리킴
• 배열 기반: 문자 변경 O, 주소 변경 X
• 포인터 기반: 문자 변경 X, 주소 변경 O
실습 1
다음 코드의 실행 결과를 확인해보세요:
#include <stdio.h>
int main() {
char arr[] = "Hello";
char *ptr = "World";
printf("배열 기반: %s\n", arr);
printf("포인터 기반: %s\n", ptr);
// 배열 기반: 문자 변경 가능
arr[0] = 'h';
printf("변경 후 배열: %s\n", arr);
// 포인터 기반: 다른 문자열을 가리킬 수 있음
ptr = "New World";
printf("변경 후 포인터: %s\n", ptr);
return 0;
}
실행 결과 보기
배열 기반: Hello 포인터 기반: World 변경 후 배열: hello 변경 후 포인터: New World
2. 문자 단위 입출력 함수
putchar와 getchar 함수
C 언어는 한 글자씩 입출력하는 함수를 제공합니다.
| 함수 | 기능 | 사용 예 |
|---|---|---|
putchar(문자) |
문자 하나 출력 | putchar('A'); |
getchar() |
문자 하나 입력 | ch = getchar(); |
기본 사용법
#include <stdio.h>
int main() {
int ch;
printf("문자 입력: ");
ch = getchar(); // 문자 하나 입력
printf("입력한 문자: ");
putchar(ch); // 문자 하나 출력
putchar('\n');
return 0;
}
실행 결과 보기
문자 입력: A 입력한 문자: A
getchar()는 int형을 반환합니다. 이는 EOF(-1) 값을 구분하기 위함입니다.
EOF (End Of File)
EOF는 파일의 끝 또는 입력 종료를 나타내는 상수입니다.
EOF가 반환되는 경우:
- 읽어 들일 데이터가 더 이상 없을 때
- Windows:
Ctrl + Z입력 - macOS/Linux:
Ctrl + D입력
실습 2 - EOF를 이용한 입력 종료
#include <stdio.h>
int main() {
int ch;
printf("문자를 입력하세요 (종료: Ctrl+Z 또는 Ctrl+D):\n");
while (1) {
ch = getchar();
if (ch == EOF) // 입력 종료
break;
putchar(ch);
}
printf("\n입력이 종료되었습니다.\n");
return 0;
}
실행 결과 보기
문자를 입력하세요 (종료: Ctrl+Z 또는 Ctrl+D): Hello Hello World World ^Z 입력이 종료되었습니다.
3. 문자열 단위 입출력 함수
puts와 gets 함수
문자열 전체를 한 번에 입출력하는 함수입니다.
| 함수 | 기능 | 사용 예 |
|---|---|---|
puts(문자열) |
문자열 출력 후 자동 줄바꿈 | puts("Hello"); |
gets(배열) |
문자열 입력 (공백 포함) | gets(str); |
gets() 함수는 버퍼 오버플로우 위험이 있어 최신 컴파일러에서는 사용이 권장되지 않습니다.
대신 fgets() 함수 사용을 권장합니다.
실습 3
#include <stdio.h>
int main() {
char str[100];
printf("문자열 입력: ");
gets(str);
printf("입력한 문자열:\n");
puts(str); // 자동으로 줄바꿈
printf("이 문장은 다음 줄에 출력됩니다.\n");
return 0;
}
실행 결과 보기
문자열 입력: Hello World 입력한 문자열: Hello World 이 문장은 다음 줄에 출력됩니다.
puts vs printf:
• puts("Hello")는 자동으로 줄바꿈
• printf("Hello")는 줄바꿈 없음 (명시적으로 \n 필요)
4. 문자열 처리 함수
C 언어는 문자열을 다루기 위한 다양한 표준 함수를 제공합니다. 이 함수들은 string.h 헤더 파일에 선언되어 있습니다.
#include <string.h>
주요 문자열 함수
| 함수 | 기능 | 반환값 |
|---|---|---|
strlen(str) |
문자열 길이 | 정수 |
strcpy(dest, src) |
문자열 복사 | dest 주소 |
strncpy(dest, src, n) |
n개 문자 복사 | dest 주소 |
strcat(dest, src) |
문자열 이어붙이기 | dest 주소 |
strncat(dest, src, n) |
n개 문자 이어붙이기 | dest 주소 |
strcmp(str1, str2) |
문자열 비교 | 0, 양수, 음수 |
strncmp(str1, str2, n) |
n개 문자 비교 | 0, 양수, 음수 |
strlen - 문자열 길이
문자열의 널 문자를 제외한 길이를 반환합니다.
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello";
char str2[] = "C Programming";
printf("str1의 길이: %d\n", strlen(str1)); // 5
printf("str2의 길이: %d\n", strlen(str2)); // 13
return 0;
}
•
strlen("Hello") → 5 (문자 개수)•
sizeof("Hello") → 6 (널 문자 포함 바이트 수)
strcpy와 strncpy - 문자열 복사
strcpy(dest, src): 전체 문자열 복사
char src[] = "Hello";
char dest[20];
strcpy(dest, src); // "Hello"가 dest에 복사됨
strncpy(dest, src, n): n개 문자만 복사
char src[] = "Hello World";
char dest[20];
strncpy(dest, src, 5); // "Hello"만 복사
dest[5] = '\0'; // 수동으로 널 문자 추가 필요!
strncpy는 n개 문자만 복사하므로 자동으로 널 문자를 추가하지 않을 수 있습니다.
반드시 수동으로 널 문자를 추가해야 합니다!
실습 4
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "apple is good";
char str2[50] = "berry is good";
char str3[50];
printf("원본 문자열:\n");
printf("str1: %s\n", str1);
printf("str2: %s\n", str2);
// str1 전체를 str3에 복사
strcpy(str3, str1);
printf("\nstrcpy 후 str3: %s\n", str3);
// str1의 5개 문자를 str2에 복사
strncpy(str2, str1, 5);
str2[5] = ' '; // 기존 문자 유지
printf("strncpy 후 str2: %s\n", str2);
return 0;
}
실행 결과 보기
원본 문자열: str1: apple is good str2: berry is good strcpy 후 str3: apple is good strncpy 후 str2: apple is good
strcat과 strncat - 문자열 이어붙이기
strcat(dest, src): src를 dest 뒤에 이어붙이기
char str[50] = "Hello ";
strcat(str, "World"); // "Hello World"
strncat(dest, src, n): src의 n개 문자만 이어붙이기
char str[50] = "Hello ";
strncat(str, "World!", 5); // "Hello World"
실습 5
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "Michael ";
char str2[50] = "Michael ";
// str1에 "Bolton" 이어붙이기
strcat(str1, "Bolton");
printf("strcat 결과: %s\n", str1);
// str2에 "Jackson Five"의 7글자만 이어붙이기
strncat(str2, "Jackson Five", 7);
printf("strncat 결과: %s\n", str2);
return 0;
}
실행 결과 보기
strcat 결과: Michael Bolton strncat 결과: Michael Jackson
strcmp와 strncmp - 문자열 비교
strcmp(str1, str2): 두 문자열 비교
| 조건 | 반환값 |
|---|---|
| str1 == str2 | 0 |
| str1 < str2 (사전순 앞) | 음수 |
| str1 > str2 (사전순 뒤) | 양수 |
strncmp(str1, str2, n): 앞 n개 문자만 비교
strcmp("apple", "apple") // 0 (같음)
strcmp("apple", "banana") // 음수 (apple이 앞)
strcmp("zebra", "apple") // 양수 (zebra가 뒤)
strncmp("apple", "application", 3) // 0 ("app"까지 같음)
== 연산자로는 문자열을 비교할 수 없습니다!if (str1 == str2) ❌ 주소 비교if (strcmp(str1, str2) == 0) ✅ 내용 비교
실습 6
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "apple";
// strcmp 예제
printf("strcmp(str1, str2) = %d\n", strcmp(str1, str2)); // 음수
printf("strcmp(str1, str3) = %d\n", strcmp(str1, str3)); // 0
printf("strcmp(str2, str1) = %d\n", strcmp(str2, str1)); // 양수
// 문자열 같은지 확인
if (strcmp(str1, str3) == 0) {
printf("\nstr1과 str3는 같은 문자열입니다.\n");
}
// strncmp 예제
printf("\nstrncmp(\"apple\", \"application\", 3) = %d\n",
strncmp("apple", "application", 3)); // 0
return 0;
}
실행 결과 보기
strcmp(str1, str2) = -1
strcmp(str1, str3) = 0
strcmp(str2, str1) = 1
str1과 str3는 같은 문자열입니다.
strncmp("apple", "application", 3) = 0
strcmp의 정확한 반환값은 컴파일러마다 다를 수 있지만, 음수/0/양수의 의미는 동일합니다.
5. 종합 실습
문제 1 - 문자열 길이 (기초)
다음 코드의 실행 결과는?
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "C Language";
printf("%d", strlen(str));
return 0;
}
문제 2 - 문자열 복사 (기초)
다음 코드의 실행 결과는?
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello";
char dest[20];
strcpy(dest, src);
dest[0] = 'h';
printf("%s %s", src, dest);
return 0;
}
문제 3 - 문자열 이어붙이기 (기초)
다음 코드의 실행 결과는?
#include <stdio.h>
#include <string.h>
int main() {
char str[50] = "Good";
strcat(str, " Morning");
printf("%s", str);
return 0;
}
문제 4 - 문자열 비교 (중급)
다음 코드의 실행 결과는? (0, 양수, 음수 중 하나)
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Apple";
char str2[] = "Banana";
int result = strcmp(str1, str2);
if (result < 0)
printf("음수");
else if (result > 0)
printf("양수");
else
printf("0");
return 0;
}
문제 5 - strncpy (중급)
다음 코드의 실행 결과는?
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Programming";
char dest[20] = "XXXXXXXXXXXX";
strncpy(dest, src, 4);
dest[4] = '\0';
printf("%s", dest);
return 0;
}
문제 6 - 배열 vs 포인터 (중급)
다음 코드에서 컴파일 에러가 발생하는 줄 번호는?
#include <stdio.h>
int main() {
char arr[] = "Hello";
char *ptr = "World";
// 6행
arr[0] = 'h';
// 9행
arr = "New Hello";
// 12행
ptr[0] = 'w';
// 15행
ptr = "New World";
return 0;
}
문제 7 - EOF (중급)
다음 중 EOF에 대한 설명으로 올바른 것은?
A. EOF는 파일의 끝을 나타내는 상수이다.
B. getchar()는 EOF를 반환할 수 있다.
C. Windows에서는 Ctrl+Z로 EOF를 입력한다.
D. 위의 모든 설명이 맞다.
문제 8 - 문자열 처리 종합 (고급)
다음 코드의 실행 결과는?
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "Hello";
char str2[50] = "Hello";
char str3[50];
strcpy(str3, str1);
strcat(str3, " World");
if (strcmp(str1, str2) == 0 && strcmp(str1, str3) != 0) {
printf("%d", strlen(str3));
}
return 0;
}
핵심 요약
• 배열 기반:
char str[] = "Hello"; (문자 변경 O, 주소 변경 X)• 포인터 기반:
char *str = "Hello"; (문자 변경 X, 주소 변경 O)2. 문자 단위 입출력
•
getchar(): 문자 하나 입력•
putchar(ch): 문자 하나 출력•
EOF: 입력 종료 (Ctrl+Z 또는 Ctrl+D)3. 문자열 단위 입출력
•
gets(str): 문자열 입력 (위험, fgets 권장)•
puts(str): 문자열 출력 (자동 줄바꿈)4. 문자열 처리 함수 (string.h)
•
strlen(str): 문자열 길이 (널 문자 제외)•
strcpy(dest, src): 문자열 복사•
strncpy(dest, src, n): n개 문자 복사•
strcat(dest, src): 문자열 이어붙이기•
strncat(dest, src, n): n개 문자 이어붙이기•
strcmp(str1, str2): 문자열 비교 (같으면 0)•
strncmp(str1, str2, n): n개 문자 비교5. 문자열 비교
•
strcmp 반환값: 0(같음), 음수(str1이 앞), 양수(str1이 뒤)•
== 연산자는 주소 비교, strcmp로 내용 비교6. 주의사항
•
strncpy는 널 문자 자동 추가 안 될 수 있음•
gets는 버퍼 오버플로우 위험 (fgets 권장)• 문자열 함수 사용 시
#include <string.h> 필수