[완료] 약간은 엉뚱(?)한 포인터 질문입니다.
안녕하세요.
이제 C책 한권정도를 보고, 프로그램을 다시한번 짜면서 확인하는 학생입니다.
코드 작성중에 포인터에 대해 궁금한점이 있어서 문의 드립니다.
좀 엉뚱한 질문이더라도 양해해 주시기 바랍니다.
void func(char ** pstr) { // 어쩌고.. 저쩌고.. *pstr = (char*)malloc(len+1); strcpy(*pstr, buf); } void main() { char * str; func(&str); printf("%s\n", str); }
보시다시피 func()함수에 포인터를 넘겨, 메모리를 할당받고 문자열을 복사받아 돌려받는 코드입니다.
이걸 하다보니 func를 이중포인터로 하지 않아도 되지 않을까? 라는 기발한(이라고 써놓고 쓸데없는 이라고 읽습니다만) 생각이 들었습니다.
void func(char * pstr) { // 어쩌고.. 저쩌고.. &pstr = (char*)malloc(len+1); strcpy(pstr, buf); } void main() { char * str; str = &str; <- 이부분 func(str); printf("%s\n", str); }
ㄴ네.. 바로 이 생각을 한 것입니다.
(1)str의 값으로 str 자신의 주소값을 넣습니다. str의 주소가 0x1234라 가정하면
str = 0x1234[쓰레기값] -> str = 0x1234[0x1234] 이렇게 되겠지요?
이걸 func의 인자로 넘깁니다.
(2)그럼 func의 인자 pstr에는 0x1234라는 주소값이 들어 있을 겁니다. 인자 pstr의 주소가 0x5678이라 가정하면
pstr = 0x5678[0x1234] 이렇게 될겁니다.
(3)pstr에 들어있는 번지0x1234에 메모리 할당을 시도합니다.
어딘가(0xABCD라 가정하겠습니다)에 할당을 하고, 그 주소를 받을테니
str = 0x1234[0x1234] 에서 -> str = 0x1234[0xABCD]가 될겁니다. 성공!!! 입니다.
이런 생각을 했는데요... ^^);
str = &str; 이 부분부터 컴파일 오류가 나더군요.
제가 어설프게 알아서 그런지 아무리 생각해도 이론상으로는 안될게 없어보이는데요.
안되는 이유가 무엇인지요?
설명 부탁드립니다. m(__)m
포인터를 넘겨준다고 해도 사실은
값을 넘겨주는 것입니다.
C 언어는 call by value 이지요.
단일 포인터를 넘겨주게 되면 그 포인터의 값을 받게 되므로 그 포인터 값이 가리키는 곳을 읽거나 변경하거나 할 수 있습니다.
그런데 포인터 자체를 변경하고 싶다고 한다면 그 포인터 변수의 주소값(즉 이중 포인터처럼 보이죠?)을 넘겨 주어야 합니다.
함수를 호출할 때 값만 넘겨주는 것입니다. 따라서 그 값에 질(?)에 따라서 무엇을 할 수 있는지가 결정되죠.
음...
무슨 말씀이신지 알듯 하면서도 잘 모르겠습니다.. ㅠ.ㅠ);;
좀더 공부하도록 하겠습니다~
답글 감사드립니다.. __);
원래
포인터는 인간의 두뇌로 잘 이해할 수 없는 것이라고들 하죠.
포인터든, 어드레스든, 객체의 주소든 그것은 뭔가를 가리키는 값 일 뿐입니다. 하지만 성깔(성격)이 다 다른 값일 수 있죠.
단순희 x = y, x = &y 이런 식으로 보기보다는 항상 (char)x = (char)y, (char *)x = (char *)y, (char *)x = (char *)&y 등으로 확인하는 습관을 들이면 좋으실 겁니다.
&y 가 char * 이라면 (char *)x = (char *)&y 가 문제가 없는 것이고,
&y 가 char ** 이라면 (char *)x = (char *)&y 는 잘못 동작하는 것이죠.
str = &str; 좌변과 우변의 타입이 다르니 될
str = &str;
좌변과 우변의 타입이 다르니 될 수가 없지요.
좌변의 타입은 char* 이고 우변의 타입은 char** 이니까요.
나머지는 이 힌트로부터 시작해서 생각해보세요~.
그러니까요..
뭔가가 다른건 알겠는데..;; 뭐가 다른건지 이해가 잘 안되서 이러고 있는듯 싶네요.
답변감사드려요~
첫째로, cleol님 말씀처럼 "char의 포인터"와
첫째로, cleol님 말씀처럼 "char의 포인터"와 "char의 포인터의 포인터"는 다른 타입입니다.
그런데 어쨌거나 포인터인 건 사실이다보니 리눅스 gcc에서 해보니 에러는 아니고 경고만 뜨더군요. 그리고 str = (char *) &str; 이렇게 캐스트해주면 경고도 안 뜹니다. (이게 제대로 수행될지는 그 다음 문제겠지만요)
둘째로, 정작 문제는
이 부분인데, malloc은 특정한 번지로 시작하는 공간을 할당하는 게 아니라 공간을 찾아서 할당하고 그 번지를 반환하니까 선후가 틀렸죠.
malloc 을 해서 0xABCD 가 반환되었다치고, 이 값이 0x1234 에 들어가야 하는데,
pstr 이 (말씀하신 표기법을 따르면)
func 진입 직후에는 pstr = 0x5678[0x1234]
malloc 수행 후에는 pstr = 0x5678[0xABCD]
까지는 되지만 이게
str = 0x1234[0xABCD]로 넘어갈 방법이 없습니다. 특히나 본문에 &pstr = 여기에 "&"를 쓰신게 오타가 아니라면, 저게 먼저 컴파일에러가 났을텐데요. &를 적용해서 얻은 주소는 lvalue가 아니니까요.
이중포인터를 정 쓰기 싫으면 그냥
이러시면 되죠. 다만 이 경우는 main쪽에서 malloc을 해야만 할 거고,
아니면 func가 번지값을 리턴하게 해서 str을 갱신하시던가요.
좋은 하루 되세요!
자세한 설명 감사드립니다.
음.. 뭔가 알듯 싶습니다.. ^^)/
"이중포인터를 쓰면 된다"는 것은 알고 있는데요, 아는것과 이해하는 것은 역시 다른가 보더라구요.
그냥 무의식중에 외워서 쓰는것 같은 느낌이 든달까요?
그래서 다시한번 보자~ 라고 디버깅 걸어가면서 주소 확인하면서 공부하다보니 저렇게 되지 않을까? 라는 생각이 들었던 것입니다.
설명을 듣고나니 말씀하신대로 str = 0x1234[0xABCD]로 넘어갈 방법없군요.
&pstr에 "&"를 쓴것은 오타가 아니라, 이런식으로 하면 이론상으로는 되지 않을까? 라는 생각으로 쓴 것입니다.
답글 감사드립니다~ 님도 좋은 하루되십시요.. ^^)
아래 코드에서 컴파일 오류 날겁니다. &pstr =
아래 코드에서 컴파일 오류 날겁니다.
&pstr = (char*)malloc(len+1);
Lvalue 어쩌구 저쩌구..
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
네~ 오류가 발생합니다.
일단 str = &str;이 왜 안되는지가 의문이었기 때문에 질문글에서 빠져있었습니다.
나름 "이론상으로 되지 않을까?"를 생각해서 적었던 코드였습니다.
답글 감사드립니다.. ^^)
어휴~ 확실히 해결 됐습니다.
여러분들 답글 읽으면서 디버깅 돌려가며 주소 확인하고, 값 확인하고 하니..
어디가 잘못된건지 확실히 이해가 됐습니다.
답글주신 분들 모두 진심으로 감사드립니다~ ^^
즐거운 주말 되시기 바랍니다.. m(__)m
댓글 달기