C언어

C언어 요점 정리 - 문자열 상수와 변수의 차이

hyestar 2022. 1. 17. 19:29

문자열 상수와 문자열 변수

문자열을 초기화하는 다음 두 가지 방법은 거의 비슷해 보이지만 근본적으로 완전히 다른 동작을 합니다.

char *s1 = "abcdefg";
char s2[8] = "abcdefg";

첫번째 s1은 프로그램이 로딩될 때 정적영역에 "abcdefg"를 저장한 다음 이 시작 주소를 s1에 대입하고, 문자열 포인터는 s1에는 나중에 다른 주소의 값을 대입할 수 있습니다. 즉, s1자체는 변경이 가능한 포인터 변수이지만, 지금 s1이 가리키고 있는 문자열은 문자열 상수이므로 이 문자열을 변경할 수 없습니다. 반대로 s2는 각각의 바이트가 모두 개별 변수처럼 취급되는 곳에 "abcdefg"를 저장되었습니다. 따라서 s2에 담겨 있는 문자열은 변경이 가능합니다.

간단한 예시를 보겠습니다. 다음 함수는 문자열을 모두 대문자로 만들어 주는 함수입니다. 

#include <ctype.h>
void strupr(char *origin) {
    char *temp = origin;
    while(*temp != '\0') {
        *temp = toupper(*temp);
    }
}

이 함수는 문자열 포인터(=문자열의 시작번지)를 인수로 받아, 각 문자를 대문자로 바꿔줍니다. toupper 함수는 표준 C 라이브러리에 포함되어 있는 함수이기에 신경쓰지 않으셔도 됩니다. 만약 이 함수에 s1을 넘기면 프로그램이 다운됩니다. 문자열 상수를 변경하려는 시도를 했기 때문입니다. 반대로 s2를 넘긴 경우에는 정상적으로 동작하는 것을 볼 수 있다. 다음은 전체 코드이다.

#include <stdio.h>
#include <ctype.h>
void strupr(char *origin);
int main(void) {
    char *s1 = "abcdefg";
    char s2[8] = "abcdefg";
    //printf("%s\n", strupr(s1)); // ==> 프로그램이 다운된다.
    printf("%s\n", strupr(s2)); // ==> 정상적으로 동작한다.
    return 0;
}
void strupr(char *origin) {
    char *temp = origin;
    while(*temp != '\0') {
        *temp = toupper(*temp);
    }
}

언뜻 생각하기에는 s2 = s1; 이라고 하면 안되나? 하는 생각이 들 수 있는데, 안됩니다. 비록 문자열 배열 변수의 변수명이 배열의 시작번지를 가리킨다고 해서 이것이 포인터라는 것은 아닙니다. 그것은 일종의 약속으로 배열의 변수명을 배열의 시작번지와 같이 다루는 것일 뿐입니다. 즉, s2는 포인터 상수이고, 방금 예를 든 저 구문은 s2의 자리에 s1의 값 (정적영역내의 "abcdefg"가 자리잡은 메모리 번지)을 대입하고자 하는 시도이고, 이는 서로 타입이 맞지 않는 대입 구문이기 때문에 에러를 유발합니다.

결론을 내리면!!!! 1) 문자열 포인터로 문자열을 초기화하면 문자열 상수가 된다. 2) 배열로 선언한 문자열에 문자열을 집어 넣을 때는 직접대입이 아니라 한글자씩 루프를 돌면서 넣어야 한다.

 

728x90