이중 포인터 읽기 질문드립니다.

kysu5095의 이미지

이중포인터가 매개변수인 함수에서 매개변수의 값을 출력하고 싶습니다.
아래 코드의 func의 매개변수값이 void형 이중포인터 val값인 1을 출력하고 싶습니다.
void형이기때문에 일단 int형 포인터로 바꿔줘야할 거 같아서 (int*)val로 바꾸고
역참조를 두번해야해서 **(int*)val이나 *&(int*)val을 해주어야 한다고 생각했는데
둘 다 오류가 뜨네요ㅠㅠ 어떤 방식으로 출력해야 하나요???

// 함수 원형
void func(void** val){
  printf("%d\n", ???);
}
 
// 전달할 인자
int val = 1;
void* deliver_val = &val;
func(&deliver_val);

라스코니의 이미지

일단 체크할 사항이 굳이 void 형으로 받을 필요가 있나요?
int *deliver_val 이 맞을까요? int **deliver_val이 맞을까요?

kysu5095의 이미지

*(int*)val << 이렇게 참조하면 val의 주솟값이 나와서요,,,

라스코니의 이미지

*(int *)val은 *val과 똑같습니다. 그래서 주소값이 나오는 것이지요.

int **deliver_val 로 하시고, func(int** val) 로 하시고, **val로 하시면 값이 나올 겁니다.

kysu5095의 이미지

답변 감사합니다. 제가 void로 사용한 것은 사용하는 함수의 파라미터가 void형으로 되어있어서 그랬습니다.
라스코니님의 형식을 응용하여 해결하였습니다. 감사합니다!!!

pynoos의 이미지

고민하실 때, void 와 void *를 다르게 생각하셔야합니다.

전자는 참조를 할 수 없지만, 후자는 포인터로서 일단 한번의 참조는 가능합니다.
(크기를 말할 때도 표준은 void에 대한 크기는 정해지지 않았습니다만 포인터는 정해져있죠.)

func가 받는 void ** val을 *val 로 참조하면 void *가 됩니다. 이것을 int *로 캐스팅하다음 다시 참조해야 int로 접근이 가능합니다.
*(int *) val

kysu5095의 이미지

*(int*)retval은 void* retval같이 일차원 포인터형이 인자로 들어올 때 값을 참조하고
더블형 포인터인 void** retval을 위와같이 참조하면 retval의 주솟값(인자로 보낸값의)이 나오더라구요..

익명 사용자의 이미지

*(int **) var 이걸 출력하면 되지 않을까요?

kysu5095의 이미지

답변 감사합니다. *(int**)var을 해요 똑같이 주솟값이 나옵니다ㅠ
compiler는 format %d expects argument of type int, but argument 3 has type int* 타입이 안맞다네요ㅠ

익명 사용자의 이미지

c에서 주로 사용하는 포인터는 *, ** 입니다. 간혹 *** 도 사용하는 경우도 있습니다.
아래 코드를 보시고, 써먹는 법을 익히면 되겠습니다. 그냥 외워서 함수로 만들어서 ruby, 자바 써먹듯이 그렇게 써먹으면 편합니다.

#include <stdio.h>
 
void func1 (void *data)
{
  printf ("%d\n", *(int *) data);
}
 
void func2 (void **data)
{
  printf ("%d\n", **(int **) data);
}
 
int main (int argc, char **argv)
{
  int i = 12345;
 
  void   *p1 = &i;
  void  **p2 = &p1;
 
  func1 (&i);
  func1 (p1);
 
  func2 (&p1);
  func2 (p2);
 
  return 0;
}

hodong@:/home/hodong $ ./exam
12345
12345
12345
12345
kysu5095의 이미지

와 정말 감사합니다. 이렇게 한번에 보니깐 확실히 이해가 잘 되네요ㅠ
추가적으로 궁금한게 있는데 func2에서 (int**)에서 *을 왜 2개 사용하신 건가요??
위 코드도 돌아가고 제가 생각한 (int*)으로 사용해도 똑같은 결과가 나오더라구요

익명 사용자의 이미지

void ** 이라서 타입을 맞추기 위해 int ** 했습니다.

void func2 (void **data)
{
  int **i = (int **) data;
  printf ("%d\n", **(int **) data);
  printf ("%d\n", **i);
}
pynoos의 이미지

아, 제가 말로 설명한 것과 코드를 잘못썼군요.

*(int *)(*val)

제 설명에 대한 코드는 위와 같아야합니다. ;-)

ymir의 이미지

#include <stdio.h>
 
void func(int **val)
{
        printf("%d\n", *(*val));
        printf("%d\n", **val);
}
 
void func2(void **val)
{
        printf("%d\n", *(int *)*(int **)val);
        printf("%d\n", **(int **)val);
}
 
int main(void)
{
        int val = 1;
        int *deliver_val = &val;
        void *deliver_val2 = &val;
 
        func(&deliver_val);
        func2(&deliver_val2);
 
        return 0;
}

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

kysu5095의 이미지

감사합니다!!. 위에 분과 마찬가지로 한번에 여러 동작을 보니 이해가 훨씬 잘 되는것 같습니다.
여기서도 궁금한게 있는데 func2에 *(int *)*(int **)val 에서 (int*)을 하고 또 (int**)을 하신 이유가 있을까요?
제 딴에서는 이해가 잘 되지 않아서요ㅠㅠ

ymir의 이미지

void 는 type 이 없기 때문에, void pointer 는 dereference 할 수 없습니다.
실제 type 을 모르면 dereference 할 때, 해당 주소에서 몇 바이트를 읽어와야 할 지 알 수 없기 때문입니다.

그래서 void ptr 로 받으면, 원하는 data type 의 ptr 로 casting 해서 써야 합니다.
원래는 **(int **)val 과 같이 바로 접근하면 되는데..
어떤 원리로 그렇게 되는지 보이기 위해 풀어서 쓴 겁니다.

dereference 연산자는 변수에 가장 가까운 녀석부터 해석됩니다.
그걸 보이기 위해 func() 에서 *(*val) 을 일부러 넣었습니다.

(int **)val 을 dereference 하면, 이 값의 type 은 int * 가 되기 때문에..
(int *)*(int **)val 과 같이 (int *) 를 붙여서 int * 임을 보인거고..

*(int *)*(int **)val 과 같이 한 번 더 dereference 하면, 원래의 int 값이 들어가게 되는거죠.
사실상 *(int **)val 의 type 은 int * 이기 때문에, 필요 없으므로 빼면 됩니다.
결과적으로 double pointer 는 **(int **)val 과 같이 ** 로 dereference 한다는 것만 남는거죠.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

익명 사용자의 이미지

명쾌한 설명입니다. 초보자분들께서는 잘 이해가 되지 않으실텐데, 일단, 포인터 써먹는 법 외우시고 포인터 써먹는데도 문제가 없게 하시고, 그렇게 시간이 1년, 2년 지나면 포인터가 뭔지 이해가 되는 때가 올 겁니다. 그 때 되면.. 아하~~~~~~~~~~~~ kldp 에서 그 ymir님이.. 한 말이 그말이구나.. 떠오를겁니다.
c 어렵다고 회피하지 마시고, 포인터 부분은 활용법을 일단 외우세요.
집에서 열공하면서 코로나를 극복합시다.
아자~~~~~~ 아자 화이팅~~~~~~~~~~!!!!!

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.