티스토리 뷰
일반 변수의 경우 이름, 주소, 그안에 저장된 정보 이 셋이 매우 명확하게 구별됩니다.
포인터는 변수 자체의 주소와 변수에 저장된 주소, 이렇게 두 개의 주소가 공존하기 때문입니다.
다중 포인터라는 것은 포인터가 가리키는 것이 포인터 변수일 뿐입니다.
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;
}
'언어 > C' 카테고리의 다른 글
구조체 - 독하게 시작하는 C프로그래밍 (0) | 2019.10.04 |
---|---|
Call by value, Call by reference - 독하게 시작하는 C프로그래밍 (0) | 2019.10.03 |
메모리 동적 할당 및 관리 - 독하게 시작하는 C프로그래밍 (0) | 2019.09.19 |
포인터와 배열 - 독하게 시작하는 C프로그래밍 (0) | 2019.09.18 |
메모리의 종류 / 직접 지정, 간접 지정 - 독하게 시작하는 C프로그래밍 (0) | 2019.09.18 |
- Total
- Today
- Yesterday
- 공간복잡도
- 구조체
- 형승격
- 간접 지정
- 비트필드
- 시간복잡도
- C
- 배열
- codeit
- 파이썬
- 공용체
- 3차원 배열
- 회전리스트
- 2차원 배열
- timecomplexity
- call by reference
- Algorithm
- 직접 지정
- inflearn
- 종류
- 재귀함수
- 프로그래밍
- 자료구조
- 1차원 배열
- 강의
- 포인터
- 다차원 배열
- 공부
- 알고리즘
- call by value
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |