본문 바로가기

ECIM list (Help!)

C언어 포인터 - 문자열을 다룰 때 이중 포인터를 쓰는 이유

1.char * word = "hello" 이렇게되있을때, char * word = 0x12 이런식으로,

문자열의 주소값을 가지고있다고 생각해서 제가 이름값만 바로 넘겨버렸었거든요;
문자열의 주소값을 바탕으로 포인터로 접근하면 된다고생각했는데 안되더라구요 ㅠㅠ. 왜그런건가요 ㅠㅠ.? 왜, 문자열의 주소값이 아니라, 문자열을 가리키고있는 포인터의 주소를 이중포인터로 받아서 접근해야하는건가요??

 

 

2.배열의 경우엔 이름이 주소값이라서 저렇게 넘겨졌구요; 제가 개념이 꼬인거같은데 이부분 조금만 설명해주시면안될까요 ..?
c언어에서 문자열을 표현할때, 포인터로 표현할때와 배열의 표현할때 차이점을요 ㅠㅠ.



   테스트를 위하여, 문자열 연산을 싱글 포인터로 바꿔봤습니다. 
 



#include  
#include 
#include 
#include 
#include 

#define DICTIONARY_SIZE 30 
//단어를 랜덤으로 하나 고름 
void PickUpProblem(char *words[], char *word2);
//문제를 만들어냄( ex> apple -> _____) 
void MakeProblem(char * answer, char ** word);


int main(void)
{
    char * words[] = { "apple","banana","carrot","dog","egg","flash","inheritance","multimedia","console","printf",
        "best","initialization","constructor","structure","file","software","hardware","animal","zoo","vaccine",
        "matlab","cat","architect","toeic","computer","java","watch","samsung","brand","vitamin" };
    char * word = NULL;
    char answer[20];

    //단어를 랜덤으로 하나 고름 
    PickUpProblem(words, word);

    //고른 단어를 바탕으로 문제 제작 
    MakeProblem(answer, &word);

    return 0;
}

void PickUpProblem(char * words[], char * word2)
{
    int i;
    srand(time(NULL));
    word2 = words[rand() % DICTIONARY_SIZE];
}
void MakeProblem(char *answer, char **word)
{
    int i;

    for (i = 0; i < strlen(*word); i++)
    {
        answer[i] = '_';
    }

    answer[i] = '\0'; //문자열의 끝을 나타내는 널문자 삽입 
}

 

 해설 : 함수 인자는 Call by Value로 넘어갑니다. 

 
PickUpProblem() 함수의 인자인 word2 는 PickUpProblem() 함수의 "지역변수" 입니다. 즉, 함수가 끝나면 이 변수는 사라집니다. 휘발성입니다.

○ Main() 함수에서 PickUpProblem() 함수를 부르면서, main() 함수의 지역변수인 word 를 인자로 넘겼습니다. 하지만, word 변수 자체를 넘긴 것이 아니라, word 함수의 주소값만 넘긴 것입니다. "값" 만 넘긴 것입니다. (Call by Value)

○ 다음은 디버거를 이용하여, word와 word2 의 메모리 주소와, 그 값이 변하는 것을 찍어본 것입니다.


1. Main() 에서 PickUpProblem() 함수를 불렀을 때 입니다. word2 변수는 아직 호출되지 않아서 알 수 없습니다.NULL로 초기화 되어 있는 상태입니다.


2. PickUpProblem() 함수 안으로 들어와서 함수 실행이 막 끝난 상태입니다.



이 때, 메모리를 열어보면, word 변수는 변화가 없습니다.

처음에 PickUpProblem() 함수가 실행되었을 때, word2에다 word 변수의 메모리 주소만 적어놓은 것이기 때문입니다.

word2 = words[] 의 값을 할당하면서, 적어놓은 메모리 주소는 지워지고, 그 위에 "vaccine" 에 해당하는 주소가 저장됩니다.




이후, PickUpProblem() 함수 실행이 끝나면 word2 변수는 지역 변수이기 때문에 날아갑니다. 원래 main() 함수의 word 변수는 아무런 변화가 없습니다.



 

 이중 포인터를 쓰는 이유  

 
○ 문자열의 경우는, Char *word 를 문자열을 저장하는 하나의 변수로 생각하는 편이 이해가 쉽습니다. 즉, int A; 처럼 String word 를 선언한 것입니다. 즉, String = char* 인 것이죠.

그럼, String word의 참조를 함수의 인자로 전달하기 위해서는 String *word 를 전달해야 합니다.

○ String = char* 라고 했으니, 다시 치환하면 char **word 가 됩니다. 이해가 되실까요? 이걸 이해하면 포인터를 진짜로 이해한 것입니다.



 

 컴퓨터 메모리의 주소와 값을 구분해서 이해할 수 있어야 합니다.  이부분이 제일 어렵습니다

 
○ 다른 방식으로 풀 수도 있습니다. 위에 예제에서, word 변수의 주소값을 인자로 넘겼습니다. 위 예제에서는 이 주소값을 활용하지 않았습니다. 

○ strcpy(word2, words[rand()%DICTIONARY_SIZE])를 호출하면 문제가 해결됩니다. word2의 주소에다 words[]의 문자열 (여기서는 vaccine) 를 직접 써넣는 함수 입니다. 이중 포인터를 쓰는 것에 비하면 값을 카피하는 시간이 걸리기 때문에 비효율적입니다.