작성
·
63
1
안녕하세요, 14.22 강의를 듣다가 함수 포인터는 아니지만 예제 속 변수의 포인터에 관한 의문이 생겨 질문 남깁니다.
1.
해당 예제를 따라하다가 toupper, tolower함수의 사용과 변수들의 저장에 대해 궁금증이 생겨 아래 코드를 작성하고 실행을 시켜 보았는데요,
void ToUpper(char* str1)
{
printf("Address of str(before toupper function operate) : %lld\n", (long long)str1);
while (*str1)
{
*str1 = toupper(*str1);
str1++;
}
printf("Address of str(after toupper function operate) : %lld\n", (long long)str1);
}
void ToLower(char* str2)
{
printf("Address of str(before tolower function operate) : %lld\n", (long long)str2);
while (*str2)
{
*str2 = tolower(*str2);
str2++;
}
printf("Address of str(after tolower function operate) : %lld\n", (long long)str2);
}
int main()
{
char str[] = "Hello World!";
void (*pf)(char*);
pf = &ToUpper;
printf("String literal: %lld\n", (long long)("Hello, World!"));
printf("Function pointer: %lld\n", (long long)ToUpper);
printf("Function pointer, pointer ver: %lld\n", (long long)pf);
printf("Variable : %lld\n", (long long)str);
printf("\n");
(*pf)(str);
printf("\n");
printf("ToUpper ver: %s\n", str);
printf("Address of str after function ToUpper Operate: %lld\n", (long long)str);
pf = &ToLower;
printf("\n");
(*pf)(str);
printf("\n");
printf("ToLowerr ver: %s\n", str);
printf("Address of str after function ToLower Operate: %lld\n", (long long)str);
return 0;
}
먼저 main 함수 내에서 str의 주소를 찍어 본 결과 "Variable : 803261380856"라는 주소값이 출력된 걸 볼 수 있고 이를 ToUpper 함수에 넣고 다시 주소를 찍어보니 "Address of str(before toupper function operate) : 803261380856"로, 같은 주소가 출력된 걸 볼 수 있었습니다. (char*로 받아줬으니 당연하겠지만요.) 이후 ToUpper 함수 내에서 toupper 함수가 포함된 while 문이 돌아간 후 다시 주소를 찍어보니 원래 값보다 12가 추가된 803261380868라는 값이 출력된 걸 볼 수 있었고, 이는 while문 내에서 str1++연산이 수행되며 *str의 각 characer를 대문자로 바꿔주는 과정이 있었기 때문에라고 생각했습니다.
의문이 생겼던 부분으로, ToUpper가 실행된 결과가 끝나고 "ToUpper ver: HELLO WORLD!"가 출력된 후, str의 주소를 다시 찍어봤는데 12가 추가된 값이 아닌 원래의 주소값이 출력이 된 걸 볼 수 있었는데요,
처음에는 ToUpper 함수의 매개변수의 데이터 타입이 char*이니, 막연하게 str의 주소도 당연히 바뀐 값이 나올 거라고 생각했었는데
생각해보니 위 경우는 포인터의 참조값을 사용한 것이 아닌 포인터 자체의 값을 연산한 것이니 call by value로 포인터 변수가 사용된 것이며, main 함수의 str과 ToUpper의 매개변수인 str1은 처음에는 가리키는 주소가 같았으나 str1의 경우 함수 내에서 가리키는 값이 증가한 후, 해당 함수가 끝날 때 같이 사라지는 지역변수로서 사용된 것이라는 결론이 나왔습니다.
제가 생각한 과정과 결과가 맞는지 궁금합니다.
2.
main 함수에서 str의 타입이 char[]로 지정이 되어 있는데, 이를 char* str로 바꾸니 런타임 에러가 나더라구요.
char* str로 문자열에 접근하는 것은 read only인 Text Segment의 주소를 가져온 것인데, ToUpper 함수 내에서 str = toupper(str)에서 값을 바꾸려는 시도 때문에 에러가 나는 것이 맞나요?
감사합니다.
답변 1
0
안녕하세요? 질문&답변 도우미 durams입니다.
추론하시는 과정이 좋네요. 함수의 매개변수가 포인터인 경우, 인자로 전달한 포인터의 값이 복사됩니다. 이 경우를 call by address 라고 일반적으로 지칭하는데요, 말씀하신대로 엄밀하게는 포인터 변수의 값을 복사해서 사용하는 call by value 에 해당한다고 볼 수 있습니다. 그러니 ToUpper
의 str1
은 main
의 str
값을 복사받아서 초기화된 별개의 포인터 변수입니다.
제가 약간 아쉬운 점은, 결정적으로 main
의 str
과 ToUpper
의 str1
이 다른 변수라는 것을 증명해보지는 않으신것 같아요. 간단한 출력으로 확인할 수 있으니, 시도해보셨으면 좋겠습니다.
네 맞습니다. char[]
와 같이 배열로 초기화한 경우에는 왜 런타임 에러가 발생하지 않는지에 대해서도 생각해보셨으면 좋겠습니다.
char str1[] = "Hello World!";
char* str2 = "Hello World!";
str1[0] = 'X'; // 가능
str2[0] = 'X'; // 불가능. 런타임 에러 발생