Google AdSense


[C] 문자열 바꾸기 by Sigel

얼마 전 C언어의 문자열 순서를 역순으로 바꾸는 퀴즈를 만난 적이 있다. "abcd"가 있다면 "dcba"로 바꿔주면 되는 간단한 문제다. 워낙 오랜만에 C언어를 보고, 갑자기 퀴즈를 만나니 당황되기도 하고 하여 약간의 실수는 있었지만 제대로 퀴즈를 풀은 것 같았다. 그리고 돌아와서 정말 그게 맞는지 테스트를 해봤는데 이게 왠걸?? 잘못된 참조로 실행이 되지 않는 것이다. TㅅT 그 코드는 다음과 같다.

#include <stdio.h>
#include <stdlib.h>

void func(char * str)
{
    int i = 0 ;
    int len = strlen(str);
    char ch;

    for(i=0 ; i<(len/2) ; i++)
    {
        ch = *(str + i);
        *(str + i) = *(str + len - i - 1);
        *(str + len - i - 1) = ch;
    }
}

int main()
{
    char * str = "abcd";

    printf("%s\n", str);
    func(str);
    printf("%s\n", str);

    return 0;
}

잘 보면..
크게 잘못된 부분은..
없다.. -ㅅ-;;
그런데 컴파일은 되지만, 실행 시에 func() 함수 내에서 오류가 발생한다. 왜 그럴까?? 지혁이와 함께 열심히 찾아본 후 KLDP에서 그 이유를 발견(char *로 할당된 스트링값을 변경하는 방법)할 수 있었다. 잘못된 부분은 func() 함수가 아니라 main() 함수에 있었다. 문자열을 생성하는데 다음과 같이 선언을 하면 저 문자열은 문자열 상수(string literal)로 된단다. (Java나 C#도 아니고, C언어인데 왜 문자열이 상수인지 혼란스럽긴 하지만..-ㅅ-;;)

char * str = "abcd";

이 부분을 다음과 같이 바꾸면 된다.

char str [] = "abcd";

C언어의 문자열은 ASCIZ(문자열의 끝을 영(zero)으로 하는 ASCII)(Toris 님의 덧글을 보고 황급히 수정 ㅋ)를 쓰는걸로 알고 있었는데.. 정말 혼란스럽긴 하다. 어떤 경우에 자바나 C#처럼 문자열을 상수로 인식해서, 수정이 불가능하게 되고 동일한 문자열은 같은 곳을 참조하는건지.. 비밀은 저 '*'와 '[]'에 있는 것 같은데.. 흐음.. -ㅅ-;;

어찌 되었든.. 다음과 같이 선언을 하면 str1은 수정할 수 없이 읽기만 가능(read-only)하게 되고, str2는 읽고 쓰기가 모두 가능하다.

char * str1 = "abcd"; // read-only
char str2 [] = "abcd"; // 읽기/쓰기 가능


+ 다행히도 퀴즈는 저 func()함수 내부만 구현하는 것이라 본 포스트 내용과 같은 문제는 없었다. ㅋ
+ 오늘 또 좋은거 하나 배웠다. :)

트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://entireboy.egloos.com/tb/3537846 [도움말]

덧글

  • Toris 2007/12/19 20:53 # 답글

    C언어의 문자열은 끝을 영(zero)으로 하는 배열로 알고 있었는데.. 0을 끝으로 하는 것이 아닙니다. 널(NULL) 문자를 끝으로 하는 것으로, 기호로 표시하자면 '\0'입니다. 이것을 숫자 0 으로 오해할 수 있으나, 이것은 개행 문자'\n'같은 문자열로, 널 문자라고 합니다. 그리고 아마 char * 형으로 선언하면.. 컴파일 할 때 메모리가 잡히는 것으로 압니다^^
    최신글에 있길래 그냥 이렇게 한마디 남기고 갑니다 - ^^
  • Sigel 2007/12/19 22:11 # 답글

    네.. '\0'이라는 것은 맞습니다. 링크된 포스트의 내용처럼 '0으로 끝나는 ASCII'를 쓰려 했던 것인데 말을 잘못 썼군요. ㅋ
    그리고 저도 char * 형은 Toris 님께서 쓰신 것처럼 생각은 하는데 정확하게 몰라서 ㅋ
  • free7942g 2008/01/24 18:15 # 삭제 답글

    *를 사용하면 리소스 영역의 메모리를 참조하게 되며, []를 사용하면 스택 영역의 메모리를 참조하는 변수가 됩니다. 그렇기 때문에 *의 경우는 *가 참조한는 주소를 바꿀 수 있지만, []의 경우 포인터 자체는 상수이므로 바꿀 수 없습니다. *의 경우는 컴파일할 때 리소스 개념으로 처리되며 []는 모든 번지에 하나하나 대입하는 코드로 치환되므로 상수로 사용되며 읽기가 빈번한 문자열의 경우에는 *가 더 빠릅니다.
  • Sigel 2008/01/24 19:17 # 답글

    홀.. 그렇군요.. 흐음.. 그래도 먼가 어려운게..-ㅅ-;;
    왜 저렇게 되도록 만든걸까요..
덧글 입력 영역