본문 바로가기
develop

어느 문자열 복사 C 프로그램의 오류

by 찬이 2012. 2. 1.
웹서핑을 하다가 우연히 C 프로그래밍 관련된 어떤 질문 글을 보게 되었습니다.
C 공부를 제법 하신 분들께는 너무나 당연하고 쉬운 문제이긴 하나,
혹시나 질문하셨던 분 혹은 같은 경우를 겪는 분께 작은 도움이 되었으면 해서 몇자 적어봅니다.

질문자께서 올리신 소스는 정확히 기억은 안나지만 대략 아래와 유사했습니다.
질문의 요지는 '이렇게 프로그램을 짜면 제대로 동작을 하긴 하는데,
왜 실행하다가 강제종료 에러가 나느냐'는 것이었습니다.

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

int main(void)
{
    char *src = "Hello World";
    char *dest = (char*)malloc(100);

    dest = src;
    printf("%s", dest);

    free(dest);
    return 0;
}

아마 Visual Studio로 디버깅시에는 "Expression: _CrtIsValidHeapPointer(pUserData)" 이라는 문구의 팝업이 뜨면서 강제종료 되는 것 같습니다.


이 문제에서 뭘 고치면 될까요...?

......

......

......

예, 그렇습니다.
dest = src 대신에 strcpy(dest, src) 를 사용하셔야 합니다.



그럼, 다음 질문을 드리겠습니다.

dest = src 는 왜 쓰면 안되는 걸까요...?
실제로 실행해보면 문자열이 잘 나오거든요....?


"문자열끼리는 복사가 안되니까" 라는 대답 예상해보구요.
포인터를 좀 더 공부하신 분이라면,
"dest 가 가리키는 주소가 변경되기 때문"이라는 식의 답을 하실 것으로 예상됩니다.


예, 그렇게 답하셨다면 다 맞습니다.

src 는 문자열이 아니라, 문자열 상수를 가리키는 포인터 변수죠.
다시 말해, src 가 "Hello World" 인 것이 아니라,
"Hello World" 라는 문자열이 있는 곳의 주소를 src 가 가리키고 있는 겁니다.
그런식으로 얘기하면, dst 는 malloc() 으로 할당받은 메모리가 아니라,
할당받은 메모리의 주소를 가리키는 포인터 변수가 됩니다.

이런 상황에서 dst = src 라는 문장의 의미는 무엇일까요?

바로 src 가 가리키고 있는 주소를 dst 에 복사,
즉 dst 도 src 가 가리키고 있는 곳을 똑같이 가리키도록 하는 겁니다.
그러면 dst 가 "Hello World"를 가리키게 되겠지요?
따라서 printf("%s", dst) 를 하게 되면 "Hello World"가 정상적으로 출력되는 것입니다.

하지만 이렇게 포인터 복사를 하는 것은 실제 데이터를 복사하는 것이 아니기 때문에,
문자열이 복사되는 것이 아닙니다.
그러므로 strcpy() 를 이용해서 문자열을 복사해야한다고 하는 것입니다.



앞으로 다시 넘어가서,
어쨌든 dst = src 를 한 후에 문자열 출력이 제대로 됐다고 합시다.
물론 malloc() 으로 할당받은 메모리 위치에 복사하려면 strcpy() 해야하는 것이 맞지만,
겉으로 보기엔 어쨌거나 동작은 했다 이거죠.

여기서 질문을 하나 더 드리죠.
프로그램이 강제종료되는 것은 왜 일까요...?
소스상으로도 printf() 한 다음에, malloc() 했던 메모리를 free() 해주는 것 밖에 없습니다.
과연 프로그램 강제종료(critical error)의 원인은 무엇이겠습니까.



뭐, 볼 것도 없습니다.
의심하셨던, 혹은 찍으셨던(?) free()가 맞습니다. 정확하게는 free(dst) 입니다.

dst 는 dst = src 에 의해서 할당받은 메모리가 아니라, 문자열 "Hello World"의 주소를 가리키고 있습니다.
그래서 free() 할때 dst 를 넘겨주게 되면, 시스템은 그러한 주소를 할당한 적이 없기 때문에 error 로 판단합니다.

그런데 단지 범위 밖의 예외처리가 아니라,
메모리 관련하여 심각한 오류 가능성을 가진 것으로 판단하게 되기 때문에 강제종료가 될 수 있습니다.




이번 문제의 난이도는 C 프로그래밍 교육과정 기준으로 중급쯤 되려나요...?
문자열 복사 방법, 메모리 할당, 포인터의 개념 등이 필요할 것으로 보입니다.



요즘 포스팅할게 없어서, 약간 끄적이고 갑니다.
새해 복 많이 받으세요.

댓글