반응형

*테스트 환경: 리눅스 (Ubuntu 11.04 이상),  gcc version 4.5.2 이하


C 프로그래밍을 하면서 유난히 혼동하기 쉬운 데이터 타입이 있다면 character array (char [])와 character pointer (char*)일 것 같다. 특히 함수에서 call by reference를 쓰면서 초기화를 해야 하는지, 메모리 할당을 해야 하는지에 대한 확신 없이 어림짐작으로 구현하다 보면 잘못된 메모리 접근으로 인해 Segmentation Fault를 심심찮게 보기도 한다.


사실 교과서에서 배운 바에 의하면 char array는 이미 메모리에 일정 크기가 할당된 변수이고, 해당 char array의 첫번째 인덱스가 char pointer이다. 코드상에서 char var[100]; 이라고 쓰면 100 바이트의 문자열이 생성되는 반면, char* var; 라고만 쓰면 데이터를 기록할 메모리 영역은 없고 포인터만 존재하게 된다.


본 글에서는 call by reference로 넘기는 문자열이 메모리가 할당된 char array여야 하는 경우와, 메모리를 할당할 필요가 없는 char pointer여도 되는 경우의 차이를 기록하였다. 여기에 쓰인 형태 외에도 문자열을 call by reference로 처리하는 다양한 방법이 존재할 수 있으며, 단지 여기서는 경험을 기반으로 한 기록임을 명시해 둔다.


먼저 파라미터로 메모리를 할당할 필요 없이 그냥 char pointer를 써도 되는 경우는, 함수 내부에서 새로운 문자열을 생성하고 해당 문자열이 local variable(지역변수)이 아닌 경우이다. 예를 들어, 아래와 같이 strtok 함수가 쓰이는 경우에는 char pointer만 있으면 된다.

void funcA(char* input, char** output){

    *output = strtok(input, " ");

}


int main(){

    char* split;

    funcA("11111 22222", &split);

    printf("%s\n", split);


    return 0;

}

(출력)

11111


strtok의 경우에는 별도로 메모리를 할당할 필요가 없어서 위와 같이 포인터만 지정해 주면 call by reference로 값을 얻을 수 있다. 이외에도 더 있겠지만 따로 조사하지 않았기에 추후에 내용을 보완하고자 한다.


위와 반대로, 함수 외부에서 char array를 생성/초기화하고 나서 해당 변수의 포인터를 함수에 넘겨줘야 하는 경우는 아래와 같다. 여기서 sprintf 함수는 자체적으로 새로운 문자열을 생성하지 않기 때문에 미리 정의된 문자열(char array)을 써야 한다. 이외에 비슷한 예로 strcpy, strcat 등이 있다.

void funcB(char* output){

    char* a = "11111";

    char* b = "22222";

    sprintf(output, "%s, %s", a, b);

}


int main(){

    char merged[10];

    memset(merged, 0, 10); // 배열값 초기화


    funcB(merged);

    printf("%s\n", merged);


    return 0;

}

(출력)

11111, 22222



반응형
블로그 이미지

Bryan_

,