[완료] 약간은 엉뚱(?)한 포인터 질문입니다.

bhdsb956의 이미지

안녕하세요.

이제 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 이지요.

단일 포인터를 넘겨주게 되면 그 포인터의 값을 받게 되므로 그 포인터 값이 가리키는 곳을 읽거나 변경하거나 할 수 있습니다.

그런데 포인터 자체를 변경하고 싶다고 한다면 그 포인터 변수의 주소값(즉 이중 포인터처럼 보이죠?)을 넘겨 주어야 합니다.

함수를 호출할 때 값만 넘겨주는 것입니다. 따라서 그 값에 질(?)에 따라서 무엇을 할 수 있는지가 결정되죠.

bhdsb956의 이미지

무슨 말씀이신지 알듯 하면서도 잘 모르겠습니다.. ㅠ.ㅠ);;
좀더 공부하도록 하겠습니다~
답글 감사드립니다.. __);

라스코니의 이미지

포인터는 인간의 두뇌로 잘 이해할 수 없는 것이라고들 하죠.

포인터든, 어드레스든, 객체의 주소든 그것은 뭔가를 가리키는 값 일 뿐입니다. 하지만 성깔(성격)이 다 다른 값일 수 있죠.

단순희 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 는 잘못 동작하는 것이죠.

cleol의 이미지

str = &str;
좌변과 우변의 타입이 다르니 될 수가 없지요.
좌변의 타입은 char* 이고 우변의 타입은 char** 이니까요.
나머지는 이 힌트로부터 시작해서 생각해보세요~.

bhdsb956의 이미지

뭔가가 다른건 알겠는데..;; 뭐가 다른건지 이해가 잘 안되서 이러고 있는듯 싶네요.
답변감사드려요~

raymundo의 이미지

첫째로, cleol님 말씀처럼 "char의 포인터"와 "char의 포인터의 포인터"는 다른 타입입니다.

그런데 어쨌거나 포인터인 건 사실이다보니 리눅스 gcc에서 해보니 에러는 아니고 경고만 뜨더군요. 그리고 str = (char *) &str; 이렇게 캐스트해주면 경고도 안 뜹니다. (이게 제대로 수행될지는 그 다음 문제겠지만요)

둘째로, 정작 문제는


(3)pstr에 들어있는 번지0x1234에 메모리 할당을 시도합니다.
어딘가(0xABCD라 가정하겠습니다)에 할당을 하고, 그 주소를 받을테니
str = 0x1234[0x1234] 에서 -> str = 0x1234[0xABCD]가 될겁니다. 성공!!! 입니다

이 부분인데, malloc은 특정한 번지로 시작하는 공간을 할당하는 게 아니라 공간을 찾아서 할당하고 그 번지를 반환하니까 선후가 틀렸죠.
malloc 을 해서 0xABCD 가 반환되었다치고, 이 값이 0x1234 에 들어가야 하는데,
pstr 이 (말씀하신 표기법을 따르면)
func 진입 직후에는 pstr = 0x5678[0x1234]
malloc 수행 후에는 pstr = 0x5678[0xABCD]
까지는 되지만 이게
str = 0x1234[0xABCD]로 넘어갈 방법이 없습니다. 특히나 본문에 &pstr = 여기에 "&"를 쓰신게 오타가 아니라면, 저게 먼저 컴파일에러가 났을텐데요. &를 적용해서 얻은 주소는 lvalue가 아니니까요.

이중포인터를 정 쓰기 싫으면 그냥

void func2(char *str) {
    strcpy( str, "world" );
}
 
void main() {
    char * str;
    str = (char *) malloc(10);
    func2(str);
}

이러시면 되죠. 다만 이 경우는 main쪽에서 malloc을 해야만 할 거고,

아니면 func가 번지값을 리턴하게 해서 str을 갱신하시던가요.

char* func3() {
    char *pstr = (char *) malloc(10);
    strcpy(pstr, "error");
    return pstr;
}
 
void main() {
    str = func3();
}

좋은 하루 되세요!

bhdsb956의 이미지

음.. 뭔가 알듯 싶습니다.. ^^)/

"이중포인터를 쓰면 된다"는 것은 알고 있는데요, 아는것과 이해하는 것은 역시 다른가 보더라구요.
그냥 무의식중에 외워서 쓰는것 같은 느낌이 든달까요?

그래서 다시한번 보자~ 라고 디버깅 걸어가면서 주소 확인하면서 공부하다보니 저렇게 되지 않을까? 라는 생각이 들었던 것입니다.

설명을 듣고나니 말씀하신대로 str = 0x1234[0xABCD]로 넘어갈 방법없군요.

&pstr에 "&"를 쓴것은 오타가 아니라, 이런식으로 하면 이론상으로는 되지 않을까? 라는 생각으로 쓴 것입니다.

답글 감사드립니다~ 님도 좋은 하루되십시요.. ^^)

IsExist의 이미지

아래 코드에서 컴파일 오류 날겁니다.

&pstr = (char*)malloc(len+1);

Lvalue 어쩌구 저쩌구..

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

bhdsb956의 이미지

일단 str = &str;이 왜 안되는지가 의문이었기 때문에 질문글에서 빠져있었습니다.

나름 "이론상으로 되지 않을까?"를 생각해서 적었던 코드였습니다.

답글 감사드립니다.. ^^)

bhdsb956의 이미지

여러분들 답글 읽으면서 디버깅 돌려가며 주소 확인하고, 값 확인하고 하니..
어디가 잘못된건지 확실히 이해가 됐습니다.

답글주신 분들 모두 진심으로 감사드립니다~ ^^
즐거운 주말 되시기 바랍니다.. m(__)m

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.