포인터 관련 질문..

someddorai의 이미지

안녕하세요..

얼마전에.. 게시판에서 KLDP는;; 초보적인 질문이 적어서.. 수준이 높은거 같다는... 글을 본거같은데...

아무래도 제가 수준을 낮추는 질문하나 하려합니다 - -;;

오렐리사의 유닉스시스템프로그래밍 svr4 을 보고 있습니다..

C 코드들은.. 보면 이해하고.. 이 함수가 어떤함수인지 이해하는...

초보단계는 띄었다고 생각하나;;;

포인터는... 이해한듯 하면서도.. 어려운 부분이 있더군요...

각설하고..

보통 C 언어 교재들을 보면 포인터를 설명할때

*(에스테리크라고하죠?) 가 1개인 포인터를 많이.. 보여줍니다.

그런데.. 실제로 사용되는 코드들을 보면.. 다중 포인터가 종종 사용되곤합니다.

** 같은 경우죠..;

void bubblesort(char **,int);

라고 함수를 선언했다면..

char형 변수의 포인터의 포인터를.. 참조하는건가요??

아니면.. **는 좀.. 다른의미(?)가 있는것인지요..

알듯.. 하면서도.. 해깔리는... 초보의 질문이었습니다 ^^;

galadriel의 이미지

이중 포인터는 포인터를 가르키고 있는 포인터 맞습니다.

int **a;
int *b;

a = &b;

이런식으로 쓰이겠죠.
함수에서는
int tempfunc( int **a)
{
// 여기서 *a는 ptr과 같은의미
// **a는 *ptr과 같은의미
}

main()
{
int *ptr;
tempfunc(&ptr);
}

알면서도 별로 안쓰고 있는것중에 하나가 **인데..
링크드 리스트나 자료구조를 구현할때 **로 넘기는 경우가 가끔씩 있지만

예를들어 새로운 노드를 포인터에 추가하고 싶을경우라든지 여러가지 경우에
**로 넘기면 추가가 쉬워지죠.

저는 포인터를 참조하는 포인터 정도로만 이해하고 있습니다.
(혹시 다른 의미를 가지고 있거나 좀더 실용적인 예가 있으면 갈쳐주세요오~)

galadriel in the tower of elves

lsj0713의 이미지

재귀적으로 이해하면 간단합니다.

char **c;

char형의 포인터형에 대한 포인터 변수 c
char형의 포인터형 = T라 할 때
T형에 대한 포인터 변수 c

그냥 일반 포인터 변수랑 전혀 다를게 없습니다.

(*c)

위의 수식은 T형에 대한 포인터 변수에 *를 사용한 것이므로 T형이 됩니다. 즉 char형에 대한 포인터형이 되겠죠.

(**c)

위의 수식은 (*(*c))와 같습니다. 즉, char형을 가리키는 것이 되겠죠.

저도 포인터를 이해하는 데 무척이나 오랜 시간이 걸렸는데, 지금 생각하면 왜 그렇게 오래 걸렸나 싶습니다. 무엇 때문이었는지 아무리 생각해도 기억이 안납니다. 이것을 보고 개구리 올챙이적 기억 못한다라고 하던가요...-_-;;

세벌의 이미지

수준 낮은 질문은 아니군요. 저는 * 한 개만 들어간 것도 머리 아프던데...

http//wiki.kldp.org/wiki.php/CLangaugeComplexDeclaration

moonzoo의 이미지

아 일단 방갑네요~

저도 오렐리의 unix system programming 책을 읽었었 거든요..

갠적으로 마니 도움이 되었던 책입니다.

먼저 예로 드신 char ** 를 이해하실 려면 ..

왜 or 언제 이중포인터를 써야 할까? 하는 입장에서 접근하는 것도

괜찮을 것 같습니다.

다음과 같은 코드를 본적이 있으실 겁니다.

int main(int argc, char **argv)

int main(int argc, char *argv[])

main으로 넘어온 argument들의 집합을 받기 위해 argv가

쓰였습니다. 이때 argument들은 char * 형인데

이러한 char * 형들의 집합을 인자로 받기 위해 char ** 형을 쓴것입니다.

실제로 사용할때는 argv[0] , argv[1], argv[2] 이런식으로 사용하죠.

위의 예는 가장 일반적인 예 입니다.

다른 예로는 int A, B 의 두 값을 swap하기 위해서 int * 형으로 인자를

받는 것과 마찬가지로

int *A, *B 의 두 값을 swap 하기 위해서는 int ** 를 써도 되겠네요..

저는 주로 처음 예로 든것(포인터 배열) 을 사용하기 위해 ** 를 사용하는

편입니다.

someddorai의 이미지

답변 감사드립니다 ^^

대충.. 감은 잡히는군요..

이제 가닥만 잡고.. 정리하면 될듯합니다 ^^

lsj0713님 말씀처럼..

이해하면 분명 쉬울텔데.... 이해하는게 어렵네요 ^^

한번 좀 생각해봐야겠습니다..

Linux 해안가에서.. 모래알 줍는중.. 언제다 주워?

someddorai의 이미지

문득.. 이런 생각이 드네요..

다중포인터..

즉 ** 은 2차원 배열과 같은것인가요?

이론적으로는.. 달라도.. 개념적으로;;

Linux 해안가에서.. 모래알 줍는중.. 언제다 주워?

lsj0713의 이미지

이중포인터와 이중배열은, 재귀적으로 적용된다는 점만 제외하면 별로 비슷한 점이 없습니다. '이론적으로는 달라도 개념적으로는...'이라는 말이 무슨 뜻인지는 잘 모르겠지만, 제가 보기엔 별로 비슷한 점이 없는 것 같습니다.

재귀적으로 적용된다는 말의 뜻은 이렇습니다. void를 제외한 모든 형에 대해서 'T형에 대한 배열'과 'T형에 대한 포인터'가 가능합니다. (void*형이 있긴 하지만 이건 void형에 대한 포인터라기 보다는 범용 포인터이므로 T형에 대한 포인터의 범주에 넣을 수는 없겠지요) 여기서 T형에는 그 자신도 포함됩니다. T형에 대한 포인터 형을 T1이라 한다면, T1형에 대한 포인터 형, 즉 이중 포인터도 가능하지요. 이건 배열도 마찬가지입니다.

이중 포인터나 이중 배열을 생각할 때에는 재귀적으로 적용된다는 점을 생각하여 바깥에서부터 하나씩 제거해나가며, 혹은 안쪽에서부터 하나씩 제거해 나가며 생각하면 간단합니다.

예를 하나 들어보면 다음과 같습니다.

int a[3][4];

이것은 array[3] of (array[4] of int) 라 할 수 있습니다. (int형에 대한 4 크기의 배열)을 원소로 갖는, 3 크기의 배열이라는 뜻이지요.

한가지 팁을 알려드리자면, 포인터와 배열의 선언을 읽는 방법중에서 추천할만한 방법은 연산자의 우선순위대로 영어문장을 만들어서 읽는 방법입니다. 위의 예를 볼 것 같으면, 배열의 이름 a에서 시작해서 연산자의 우선순위를 따라가면 [3] -> [4] 순이지요. 이 순서대로 영어 문장을 만들면...

array[3] of array [4] of int

포인터가 끼어도 역시 마찬가지 방법으로 해석 가능합니다.

int *a[4];

* 보다는 [] 가 우선순위가 높으므로

array[4] of pointer to int

int를 가리키는 포인터 형에 대한 배열이 되겠습니다.

아무리 복잡한 선언이라도 식별자의 이름의 위치만 찾을 수 있다면 이런 방식으로 얼마든지 기계적으로 간단하게 해석할 수 있습니다.

nahanjang의 이미지

제가 가장 먼저 **를 이해한건 문자열을 다루때 였습니다.
예를 들어
"abcd"
"efgh"
"ij"
...
이런식으로 문자열이 들어 올수 있다고 할때
이걸 char[][] 배열로 또는 char *[] 로 처리하기는 먼가가 부족하거든요.
문자열 수가 미리 고정 되어있다면 상관없지만 항상 변화 한다면 ...
이럴땐 가장 좋은게 char ** 인거 같구요..
또한 마찬가지로 구조체를 다룰때도 그런거 같네요.
특히 구조체를 사용 하다보면 ***까지 가는 경우도 종종 있구여...

bugslife의 이미지

이중 포인터가 이차원 배열과 동일한 개념이라고 하기는 어렵지만...

char **a와 char a[][]처럼 사용하는데 무리는 없습니다. 주로 문자열의 집합을 사용할때 사용되는데... 코딩시 필요에 의해 몇번의 조작(?)을 하다보면 번갈아 사용하기도 하죠. (별로 잘하는짓 같지는 않지만.. ^^)

하지만 주의하실 점이.. 고정된 배열의 경우 초기화같은 과정을 거쳐 깔끔(?)하게... 예상치 못한 값이 나오는 것이 적은 반면.. 포인터를 사용하면.. 쓰레기 값이 튀어나오거나 컴파일은 잘 됐지만 런타임시에 오류가 나는 경우가 종종 있습니다.

어느순간부터인가 하루살이의 하루를 알고싶다.

jbkdd의 이미지

저 같은 경우는 주로 함수 내부에서 선언된 포인터에 들어 있는 주소 자체를 바꿀때 많이 쓰는데요. 예를 들면.

#include<stdio.h>

int dbpoint(char **p);

int main(int argc, char* argv[])
{
char *p;
p = (char *)malloc( sizeof(char) *4);
dbpoint(&p);
..............
}

int dbpoint(char **p)
{
char buf[4];
memcpy(buf, *p,sizeof(char) *4 ) ;
free(*p);
*p = (char *)malloc(sizeof(char) *8 ) ;
}
컴파일러가 없어서 맞는지 확인은 못해봤는데 대략 저런 형식입니다.
함수 내부에서 선언된 포인터를 다시 함수를 호출하여 포인터변수에 실제 들어있는 주소를 바꿔야 할때, 즉 함수를 이용하여 포인터변수내의 실제 주소를 바꿔야 할때 씁니다. :oops:
아주 예전 책인데 가남사에서나온 [C포인터 이렇게 활용한다] 추천합니다.
포인터 공부하는데는 이만한 책이 없네요. 저에게 있어서는...
틀린곳 있다면 지적 바랍니다.

choissi의 이미지

포인터와 관련해서 헛갈릴 땐 cdecl로 확인해봅니다.

Quote:
cdecl, c++decl - Compose C and C++ type declarations

울랄라~ 호기심 천국~!!
http://www.ezdoum.com

BSK의 이미지

someddorai wrote:
;
void bubblesort(char **,int);

포인트의 포인트는 다루는 대상체가 포인트 변수입니다.

사용예는 두가지입니다.

매개변수가 포인트 변수인 것, 명령형 인자입니다.

/* ....맑은 정신, 건강한 육체, 넓은 가슴으로 세상과 타협하자. */

jachin의 이미지

꼭 날짜를 확인해 주세용.

2004년 글이거든요... T-T

죠커의 이미지

someddorai wrote:
void bubblesort(char **,int);

라고 함수를 선언했다면..

char형 변수의 포인터의 포인터를.. 참조하는건가요??

아니면.. **는 좀.. 다른의미(?)가 있는것인지요..

알듯.. 하면서도.. 해깔리는... 초보의 질문이었습니다 ^^;

char **를 더 쉽게 이해하기 위해서 char **a라고 봅시다.

여기에서 명칭을 찾습니다. char **a;

명칭에서 제일 가까운 것은 char **a; 입니다. *를 pointer to... 라고 읽읍시다.

두번째로 가까운 것은 char **a;입니다. *를 pointer to라고 읽으면 pointer to pointer to... 가 됩니다.

이제 자료형 만 남았습니다. char **a; pointer to pointer to char가 됩니다.

따라서 char를 가리키는(포인터) 것을 가리키는 것(포인터)가 됩니다.

lsj0713님이 말씀하신 것도 다시 이야기하고 변형된 형태도 봅시다.

int *a[4];

명칭을 수식하는 것은 *<포인터>와 []<배열>, ()<함수>가 있는데 *가 낮고 []와 ()는 동급입니다.

일단 명칭을 찾습니다. int *a[4];

명칭 주위에 수식하는 것은 *와 [4]입니다. 처음에 언급한 듯 []가 더 우선순위가 높기 때문에 [4]를 먼저 읽어야 합니다. int *a[4]; array 4 of...

다음으로 *를 해석합니다. int *a[4]; array 4 of pointer to...

마지막으로 자료형을 붙입니다. int *a[4]; array 4 of pointer to int

따라서 int를 가리키는 것(포인터)의 4개짜리 배열입니다.

이제 변형된 형태를 봅시다.

int (*a)[4];

먼저 명칭을 찾습니다. int (*a)[4];

다음으로 명칭을 수식하는 것은 *입니다. 괄호로 쌓여있기 때문입니다. int (*a)[4]; pointer to...

그 후에 [4]로 수식됩니다. int (*a)[4]; pointer to array 4 of...

마지막으로 자료형이 붙습니다. pointer to array 4 of int

따라서 int형의 4개짜리 배열을 가리키는 것(포인터)이 됩니다.

hyperhidrosis의 이미지

오래된 글이 광고 봇때문에 기어나오게 되었지만
읽어 보니 참 좋은 내용이네요 ^^

위에서
http://wiki.kldp.org/wiki.php/CLangaugeComplexDeclaration

를 언급하셔서 읽어 보았습니다.
평소 복잡한 포인터를 어떻게 읽을것인가... 에 대해서 고민하였는데
거기에 대해서 많은 도움을 주는 글이더군요.

하지만 궁금한 점이 또 생겨 버렸습니다.
저 링크에서 제시하는 방법에서 맨 처음 시작은

Quote:
int *a;

먼저 이름을 찾아야 합니다. 위 선언에서 "a"가 이름이니까, "a"부터 읽어나가면 됩니다. a에서 가장 먼저 결합하는 기호는 "*"입니다. 따라서 위의 표를 참고로 하여 읽으면 다음과 같습니다:

라고 되어 있는데, 여기서 "먼저 이름을 찾아야 합니다" 부분에 대한
문제점 입니다.

이름을 찾는 부분이 도저히 기계적이지가 않기 때문에 ( 함수 포인터의 파라메터
로 이름이 들어가 있으면, 이것이 함수 포인터의 이름인지부터 판단하는 작업이
필요해지게 됩니다. ) 기계적 해석이 불가능 합니다.

그래서 자료를 뒤지던중
http://bbs.kldp.org/viewtopic.php?p=348334
를 찾았고 다시 여기서
http://www.lysator.liu.se/c/ANSI-C-grammar-y.html#declarator
에 대한 링크를 찾았습니다.

Quote:
declarator
: pointer direct_declarator
| direct_declarator
;

direct_declarator
: IDENTIFIER
| '(' declarator ')'
| direct_declarator '[' constant_expression ']'
| direct_declarator '[' ']'
| direct_declarator '(' parameter_type_list ')'
| direct_declarator '(' identifier_list ')'
| direct_declarator '(' ')'
;

pointer
: '*'
| '*' type_qualifier_list
| '*' pointer
| '*' type_qualifier_list pointer
;

이 문법을 가지고 기계적으로 문법을 해석하는것을 설명하려면
어떻게 해야 하나... 생각해 보고 있습니다.

cheeky의 이미지

Quote:
int *a;
먼저 이름을 찾아야 합니다. 위 선언에서 "a"가 이름이니까, "a"부터 읽어나가면 됩니다. a에서 가장 먼저 결합하는 기호는 "*"입니다. 따라서 위의 표를 참고로 하여 읽으면 다음과 같습니다:

여기서 이름이란 name 즉, identifier로 보시면 될 것 같습니다. 따라서 알파벳 또는 _으로 시작하여 알파벳, 숫자, _가 이루는 문자열이라는 정의를 생각하면 간단히 type에 대한 Keyword(int, long 등), *, () 등을 무시하고 남은 녀석 만을 고려하면 충분히 이름인지 아닌지는 판단할 수 있지 않을까 생각합니다. ^^ 그리고나서 ()가 붙어있는 함수인지 아닌지 그리고 * []의 우선순위도 고려하구요.
Quote:
declarator
: pointer direct_declarator
| direct_declarator
;

direct_declarator
: IDENTIFIER
| '(' declarator ')'
| direct_declarator '[' constant_expression ']'
| direct_declarator '[' ']'
| direct_declarator '(' parameter_type_list ')'
| direct_declarator '(' identifier_list ')'
| direct_declarator '(' ')'
;

pointer
: '*'
| '*' type_qualifier_list
| '*' pointer
| '*' type_qualifier_list pointer
;


이런 녀석들을 이해하기 위해서는 형식언어, 컴파일러 등의 수업을 들으시면 됩니다. 저는 땡땡이로 들어서 패스~~ :evil: 이건 다른 분들이 알려주실 것입니다.

ps. 스팸이 이 글타래를 올려줬네용;; ㅡ.ㅜ

--------------------------------------------
http://blog.tinydesk.com

only2sea의 이미지

덧붙이자면 C에서 다차원 배열은 다중 포인터가 아니라 단일 포인터입니다. 다중 포인터를 다차원 배열과 비슷한 노테이션으로 사용할 수는 있겠지만요.

이유인 즉, 다차원 배열은 네모 반듯하기 때문에 궂이 그렇게 하지 않고 i*j*k*... 등으로 갯수만 구해서 일차원으로 만들어주는 것이 효율성 면에서 더 낫기 때문이죠. 결국 컴파일하기 전에만 다차원 배열이고 컴파일 후에는 첨자 계산해서 일차원 배열 쓰는 것과 똑같은 결과가 나오겠죠.

someddorai wrote:
문득.. 이런 생각이 드네요..

다중포인터..

즉 ** 은 2차원 배열과 같은것인가요?

이론적으로는.. 달라도.. 개념적으로;;

kuaaan의 이미지

jdkbb님께서 좋은 예를 들어주셨는데요...

한가지 더 덧붙이자면...

2중포인터를 인자로 해서 함수를 정의하는 경우는...

함수 내에서 할당된 메모리에 대한 주소를 리턴받고자 할때 사용합니다.

void testfunc1(int* i)
{
   *i = 1;
   return;
}

int main()
{ 
	int j;
	testfunc1(&j);
	printf("%d\n", j);
	return 0;
}

일반적인 자료형이라면 위와 같이 하여 돌려받을 수 있겠지만,

돌려받고자 하는 주소가 포인터의 주소인 경우,

2중포인터를 사용해야 돌려받을수 있습니다.

(리턴받을 값이 char* 문자열이나... 배열인 경우...)

void testfunc2(char** i) 
{ 
   *i = (char*)malloc(sizeof(char) * 5); 
   strncpy(*i, "abc", 4);
   return; 
}

int main()
{
	char* i;
	testfunc2(&i);
	printf("%s\n", i);
	delete i;
	return 0;
}

----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------

댓글 달기

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