C언어 string 배열 및 포인터 선언 예제 및 특징 비교
C언어에서 문자열(string) 자료를 char 배열로 선언하는 경우와
포인터를 이용하여 선언하는 경우의 예시 코드를 살펴보고,
이 두 문자열 선언 경우의 특징을 비교해보도록 하겠습니다.
배열(array) 이용 문자열 선언 예시
C언어에서는 C++과 달리 string을 직접적으로 다룰 수 있는 자료형이 없어
각 글자에 대한 char 변수들의 배열 혹은 포인터 형태로 선언을 해야합니다.
그렇다면 먼저 array를 통한 문자열 선언 방법을 살펴보겠습니다.
char 배열을 통한 string 선언을 그림으로 도식화하면 다음과 같습니다.
편의상 메모리 주소는 200부터 시작하는 것으로 가정하였습니다.
각 글자를 나타내는 char 자료형의 크기는 1 바이트이므로,
1글자 당 주소의 크기도 1씩 증가하는 것을 알 수 있습니다.
문자열의 인덱스는 배열과 마찬가지로 0번부터 시작하며,
문자열의 맨 마지막 자료는 종료를 알리는 null(\0) 글자가 포함되는 것에 유의해주세요.
전체 글자의 수를 셀 때 마지막 null 문자도 반드시 포함시켜야 합니다.
C언어 내에서 배열을 통하여 문자열을 선언하는 실제 예시 코드는 아래와 같습니다.
#include <stdio.h>
int main(){
// 크기 수동 지정 배열 형태 선언
char a[6] = "good!";
char b[10] = "good!"; // 크기를 넉넉하게 선언한 경우
// 크기 자동 지정 배열 형태 선언
char c[] = "good!";
// 잘못된 선언 형태
char d[4] = "good!"; // 크기를 부족하게 선언한 경우
char e = "good!"; // 단순 char로 선언 불가
char f[] = 'good!'; // 따옴표 문제
}
char 글자와 다르게 쌍따옴표(" ")로 문자열을 묶어서 지정해주어야 하며,
"good!"의 경우 g, o, o, d, !, null로 총 6글자 이므로
최소 6칸 이상의 공간을 할당해주어야 합니다.
c[] 예시처럼 글자수 칸을 비우고 선언하는 방법도 가능하며,
이 경우 글자수인 6칸으로 배열의 크기가 자동으로 정해집니다.
포인터(pointer) 이용 문자열 선언 예시
char 자료형의 주소를 가리키는 포인터 형태로도 string 선언 취급이 가능합니다.
포인터를 활용한 문자열의 선언 원리를 도식화하면 아래 그림과 같은데,
근본적으로 배열을 이용한 선언 경우와 구조는 거의 비슷함을 알 수 있습니다.
마지막에 null 문자가 포함되는 원리도 동일하며,
a[0], a[1]처럼 배열과 동일한 형태의 인덱싱 역시 지원합니다.
아래는 포인터를 이용한 문자열의 선언 예시 및 배열 형태와 출력 결과를 비교한 코드입니다.
#include <stdio.h>
int main(){
// 포인터 형태 문자열 선언
char *a = "good!";
// 배열 선언 형태와 비교
char b[] = "good!";
// 앞의 두 글자씩을 출력하여 비교
printf("%c, %c\n", a[0], a[1]); // g, o
printf("%c, %c\n", b[0], b[1]); // g, o
// 문자열 전체 출력
printf("%s\n", a); // good!
printf("%s\n", b); // good!
}
문자열 전체를 출력하는 경우 포맷팅 양식은 %s인 점도 참고해주세요.
앞 두 글자와 문자열 전체를 출력한 결과는 두 선언 형태에서 모두 동일했습니다.
배열 및 포인터 형태 문자열 선언 특징 비교
대표적인 두 문자열 선언 형태의 차이 중 하나는 할당된 메모리 영역의 크기가 다르다는 것입니다.
이를 직접 비교하기 위해 sizeof 함수를 적용해본 결과는 아래와 같습니다.
#include <stdio.h>
int main(){
char *a = "good!"; // 포인터 형태 선언
char b[] = "good!"; // 배열 형태 선언(크기 자동 할당)
char c[10] = "good!"; // 크기를 넉넉하게 선언한 경우
int a_size = sizeof a; // 8(포인터 자료형 크기)
int b_size = sizeof b; // 6(배열 크기)
int c_size = sizeof c; // 10(배열 크기)
printf("%d %d %d\n", a_size, b_size, c_size); // 8 6 10
}
배열 선언의 경우, 할당된 배열의 크기 만큼의 메모리를 차지하나
포인터 선언의 케이스에서는 포인터의 크기인 8 바이트를 문자열 길이에 상관없이
고정으로 가지게 됩니다.
또한, 배열 선언 형태의 문자열은 일부 글자 변경이 가능하나,
포인터 선언의 경우에는 일부 글자 변경이 불가능하다는 큰 특징 차이가 있습니다.
#include <stdio.h>
int main(){
char *a = "good!"; // 포인터 형태 선언
char b[] = "good!"; // 배열 형태 선언
// 일부 글자 변경 시도
b[3] = 'b'; // "goob!" 으로 변경 완료
a[3] = 'b'; // 변경 불가(segmentation fault 발생)
}