티스토리 뷰

일반 변수의 경우 이름, 주소, 그안에 저장된 정보 이 셋이 매우 명확하게 구별됩니다.

 

포인터변수 자체의 주소와 변수에 저장된 주소, 이렇게 두 개의 주소가 공존하기 때문입니다.

 

다중 포인터라는 것은 포인터가 가리키는 것이 포인터 변수일 뿐입니다.

 

int형 변수에 대한 포인터는 'int*'로 기술하며, int*변수에 대한 포인터는 'int**'로 기술합니다. 그리고 선언된 포인터 변수에 대해 간접지정 연산을 수행한 결과는 포인터의 대상 자료형에서 '*'하나를 지운 것과 같습니다.

 

포인터 자료형 간접지정 연산결과 코드 예
char * *(char *) == char

int nData = 10;

int *pnData = &nData;

char* * *(char **) == char* int* *ppnData = &pnData;
char** * *(char ***) == char** int** *pppnData = &ppnData;

 

char*의 배열

 

다중 포인터가 등장하는 흔한 이유는 '포인터의 배열' 때문입니다. 포인터 배열이란 배열의 요소가 포인터 변수인 경우를 말합니다. 

 

char형 배열은 문자(배)열일 수 있습니다. 그리고 배열은 0번 요소의 주소로 식별됩니다.

그러므로 배열을 식별하는 주소는 배열(char[5])을 이루고 있는 요소 자료형(char)에 대한 포인터(char*)에 담습니다.

 

그리고 %s 형식문자는 자료형이 char*에 대응해야 하며, %c는 char형에 대응해야 합니다.

 

#include<stdio.h>

int main(void) {
	// char* [3] 배열을 각각의 문자열로 초기화
	char* astrList[3] = { "Hello", "World", "String" };

	// 배열의 요소가 char*이므로 %s로 출력하는 것이 맞다. char**
	printf("%s\n", astrList[0]);
	printf("%s\n", astrList[1]);
	printf("%s\n", astrList[2]);

	// 배열의 0번 요소에는 첫 글자가 저장된 메모리의 주소가 들어 있다.
	// 여기에 정수를 더해 '상대주소'를 계산한다. char*
	printf("%s\n", astrList[0] + 1);
	printf("%s\n", astrList[1] + 2);
	printf("%s\n", astrList[2] + 3);

	// char*의 배열은 논리적으로 char의 2차원 배열과 같다. char
	printf("%c\n", astrList[0][3]);
	printf("%c\n", astrList[1][3]);
	printf("%c\n", astrList[2][3]);
	return 0;
}

1차원 구조의 자료형 두 종류(포인터 배열과 문자 배열)가 묶여서 논리적인 2차원 구조가 만들어졌습니다.

 

포인터와 포인터가 가리키는 대상이 선으로 연결되어 있고 '*'표시가 붙어 있는데 보통 이 선에 대해 설명할때 '따라가다'라는 말을 합니다. 즉, 포인터가 가리키는 대상을 따라가면 어떤 형식의 데이터가 나온다는 의미입니다.

 

char* 배열의 주소를 담을 수 있는 포인터 변수의 자료형은 char**입니다.

 

astrList[1][3]을 풀어서 표시하면 *(*(astrList + 1) + 3)입니다. 

 

*(*(astrList + 1) + 3) == *(*(char**)) == **(char**)

 

 

주소연산과 간접지정연산은 서로 정반대되는 개념의 연산자입니다. 만일 이 두 연산자가 괄호 안이나 밖에서 연속될 경우 무시할 수 있습니다. 예를 들어, char* astrList[3]가 선언되었고, &astrtList[1]이라는 연산이 수행되었다면 이 연산결과의 자료형은 char**가 됩니다. '&astrList[1]'을 풀어서 쓰면 &*(astrList + 1)입니다. 이때, '&*'는 서로 상쇄됩니다.

 

다중 포인터

#include<stdio.h>

int main(int argc, char* aargv[]) {
	char ch = 'A';
	//char*에는 char형의 주소를 담는다.
	char* pData = &ch;
	//char**에는 char*형의 주소를 담는다.
	char** ppData = &pData;
	//char***에는 char**형의 주소를 담는다.
	char*** pppData = &ppData;

	//아래 코드들은 모두 char  형식을 %c로 출력한다.
	printf("%c\n", ch);
	printf("%c\n", *pData);
	printf("%c\n", **ppData);
	printf("%c\n", ***pppData);
	return 0;
}

해당 코드의 메모리상황

#include<stdio.h>

int main(int argc, char* argv[]) {
	char* astrList[3] = { "Hello", "World", "String" };
	//astrList의 요소 형식이므로 char**에 담는다.
	char** ppstrList = astrList;
	//char** 형식 변수의 주소는 char***에 담는다.
	char*** pppstrList = &ppstrList;

	//*(char** + 인덱스)의 형식 char*이다.
	//따라서 %s로 출력하거나 puts()로 출력한다.
	puts(*(ppstrList + 0));
	puts(ppstrList[1]);
	puts(ppstrList[2]);

	//char***를 두 번 간접지정하면 char*이다.
	puts(*pppstrList[0]);
	puts(*(*(pppstrList + 0) + 1));
	return 0;
}

 

다차원 배열에 관한 포인터

 

2차원 배열이라는 것은 요소가 배열인 배열입니다.

 

그러므로 char[3][16] 배열은 char[16]가 요소이고 개수가 3인 배열이며 배열의 식별자인 주소를 담을 수 있는 포인터 변수는 char[16] *라 할 수 있습니다.

 

그러나 이렇게 표현한다면 문법오류입니다.

한단계 더 처리해야 문법적으로 바른 다차원 배열에 대한 포인터 변수를 선언 할 수 있습니다.

 

#include<stdio.h>

int main(int argc, char* argv[]) {
	char astrList[2][12] = { "Hello", "World" };
	//char **pstrList = astrList; 틀린 코드
	char (*pstrList)[12] = astrList;

	puts(pstrList[0]);
	puts(pstrList[1]);

	return 0;
}

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함