6. 포인터 - 다차원 배열
728x90

1. 포인터
더보기

#include <stdio.h>
void main()
{
int iNum = 97;
printf(" iNum 변수의 정수값: %d\n", iNum);
printf(" iNum 변수의 주소값: %p\n", &iNum);
int *p_iNum = &iNum;
printf(" p_iNum 포인터 변수값: %p\n", p_iNum);
printf("*p_iNum 포인터 역참조: %d\n",*p_iNum);
}
/* 실행결과
iNum 변수의 정수값: 97
iNum 변수의 주소값: 0x7fffffffdd9c
p_iNum 포인터 변수값: 0x7fffffffdd9c
*p_iNum 포인터 역참조: 97 */

2. 다차원 포인터
더보기

#include <stdio.h>
void main()
{
int iNum = 90;
printf(" iNum 변수의 정수값: %d\n", iNum);
printf(" iNum 변수의 주소값: %p\n", &iNum);
int *p_iNum = &iNum;
printf("p_iNum 포인터 변수값: %p\n", p_iNum);
int *ptr1 = p_iNum; // 이건 됨
// int *ptr1 = &p_iNum; // 이건 안됨
// 포인터 변수가 저장된 공간의, 첫번째 바이트 주소값을 담으려면?
int **ptr2 = &p_iNum;
printf(" ptr 포인터 변수값: %p\n", ptr2);
printf(" *ptr 포인터 변수값: %p\n", *ptr2);
printf(" **ptr 포인터 변수값: %d\n", **ptr2);
}
/*
iNum 변수의 정수값: 90
iNum 변수의 주소값: 0x7ffdefe9c374
p_iNum 포인터 변수값: 0x7ffdefe9c374
ptr 포인터 변수값: 0x7ffdefe9c378
*ptr 포인터 변수값: 0x7fff8d7763a4
**ptr 포인터 변수값: 90 */

3. 다차원 배열
더보기





3.1 배열 선언과 값 할당
:아래 1차원, 2차원, 3차원 모든 배열은, 값이 순차적으로 동일한 방식으로 저장된다.(!중요)
그러므로, 첫번째 바이트의 주소값만 알고 있다면, 모두 포인터 연산으로 접근 가능하다.
차이는, 다차원 배열의 문법적 사용법을 구분해 이해해야 한다.
#include <stdio.h>
int main(void)
{
char cArr0[6] = "ABCDEF";
char cArr1[6] = {1, 2, 3, 4, 5, 6};
char cArr2[6] = { 'A', 'B', 'C', 'D', 'E', 'F'};
char cArr3[2][3] = { 'A', 'B', 'C', 'D', 'E', 'F'};
char cArr4[2][3] = {{'A', 'B', 'C'}, {'D', 'E', 'F'}};
char cArr5[3][2] = {{'A', 'B'}, {'C', 'D'}, {'E', 'F'}};
return 0;
}
3.2 1차원 배열의 순차 저장과 포인터 연산
배열명은, 메모리 주소값을 가진 숫자이므로, 산술연산이 가능하다.
#include <stdio.h>
int main(void)
{
char cArr[6] = "ABCDEF";
// char cArr[6] = {65, 66, 67, 68, 69, 70};
// char cArr[6] = {'A', 'B', 'C', 'D', 'E', 'F'};
printf(" cArr+0 : %p %c\n", cArr+0, *(cArr+0));
printf(" cArr+1 : %p %c\n", cArr+1, *(cArr+1));
printf(" cArr+2 : %p %c\n", cArr+2, *(cArr+2));
printf(" cArr+3 : %p %c\n", cArr+3, *(cArr+3));
printf(" cArr+4 : %p %c\n", cArr+4, *(cArr+4));
printf(" cArr+5 : %p %c\n", cArr+5, *(cArr+5));
printf("\n");
return 0;
}

3.3 다차원 배열의 저장과 포인터 연산
다차원 배열은, 1차원 형태(크기)의 배열이 하나의 요소로 담겨있는 구조의 문법을 사용한다.
다차원 배열의 배열명(cArr2d)은, 포인터(cArr2d[0])가 아닌, 다중포인터(cArr2d)이다.
(1차원 배열명은 포인터이다. 포인터를 포인터 변수에 담으려면 다중 포인터 변수에 담아야한다.)
#include <stdio.h>
int main(void)
{
char cArr2D[2][3] = {{'A', 'B', 'C'}, {'D', 'E', 'F'}};
printf(" cArr2D+0 : %p %c\n", cArr2D+0); // 0xAAB0 // +3byte char 배열[3] 크기만큼 증가
printf(" cArr2D+1 : %p %c\n", cArr2D+1); // 0xAAB3
printf(" cArr2D+2 : %p %c\n", cArr2D+2); // 0xAAB6
printf(" cArr2D+3 : %p %c\n", cArr2D+3); // 0xAAB9
printf(" cArr2D+4 : %p %c\n", cArr2D+4); // 0xAABC
printf(" cArr2D+5 : %p %c\n", cArr2D+5); // 0xAABF
return 0;
}

3.4 프로그래밍 언어의 문법적 기호에는 모두 의미가 있다.
#include <stdio.h>
int main(void)
{
// b. 배열의 할당과 내부 구조는 동일하다.
char b1[6] = { 'A', 'B', 'C', 'D', 'E', 'F'};
char b2[2][3] = {{'A', 'B', 'C'}, {'D', 'E', 'F'}};
printf("b2: %p, | b2[0]: %p, | b2[0][0]: %c\n", b2, b2[0], b2[0][0]);
printf("b2: %p, | b2[0]: %p, | *(b2[0]) : %c\n", b2, b2[0], *(b2[0]));
printf("b2: %p, | *(b2+0): %p, | **(b2+0) : %c\n", b2, *(b2+0), **(b2+0));
printf("\n");
printf("b2: %p, | b2[1]: %p, | b2[1][0]: %c\n", b2, b2[1], b2[1][0]);
printf("b2: %p, | b2[1]: %p, | *(b2[1]) : %c\n", b2, b2[1], *(b2[1]));
printf("b2: %p, | *(b2+1): %p, | **(b2+1) : %c\n", b2, *(b2+1), **(b2+1));
printf("\n");
printf("b2: %p, | (*b2)+1: %p, |*((*b2)+1)) : %c\n", b2, (*b2)+1, *((*b2)+1));
printf("\n");
return 0;
}
// 이중포인터 | 포인터 | 값
// b2: 0x7ffc052686cc, | b2[0]: 0x7ffc052686cc, | b2[0][0]: A
// b2: 0x7ffc052686cc, | b2[0]: 0x7ffc052686cc, | *(b2[0]) : A
// b2: 0x7ffc052686cc, | *(b2+0): 0x7ffc052686cc, | **(b2+0) : A
// b2: 0x7ffc052686cc, | b2[1]: 0x7ffc052686cf, | b2[1][0]: D
// b2: 0x7ffc052686cc, | b2[1]: 0x7ffc052686cf, | *(b2[1]) : D
// b2: 0x7ffc052686cc, | *(b2+1): 0x7ffc052686cf, | **(b2+1) : D
// b2: 0x7ffc052686cc, | (*b2)+1: 0x7ffc052686cd, |*((*b2)+1)) : B

cArr 의미: 이중 포인터
cArr[ ] 의미: 포인터
cArr[ ][ ] 의미: 값
*(cArr + 0) 의미: 이중 포인터에 +0 연산(+3byte, 배열 행 크기만큼) 후, 이중포인터를 역참조하여 포인터 찾음.
(*cArr) + 0 의미: 이중포인터의 역참조하여 포인터를 찾고 +0 산술연산
배열 첫번째 바이트 주소값을 포인터 변수에 담아서 사용해보기
#include <stdio.h>
int main(void)
{
char arr[6] = {'A', 'B', 'C', 'D', 'E', 'F'};
char *ptr = arr;
printf(" ptr+0 : %p %c\n", ptr+0, *ptr+0);
printf(" ptr+1 : %p %c\n", ptr+1, *ptr+1);
printf(" ptr+2 : %p %c\n", ptr+2, *ptr+2);
printf(" ptr+3 : %p %c\n", ptr+3, *ptr+3);
printf(" ptr+4 : %p %c\n", ptr+4, *ptr+4);
printf(" ptr+5 : %p %c\n", ptr+5, *ptr+5);
return 0;
}

#include <stdio.h>
int main(void)
{
char arr3D[2][2][3] = {
{
{'A', 'B', 'C'},
{'D', 'E', 'F'}
},
{
{'G', 'H', 'I'},
{'J', 'K', 'L'}
}
};
//(void *) 생략
// Layer 0
printf("┌─────────────────── 3D 배열 구조 ────────────────────────┐\n");
printf("│ arr3D : %p\n", arr3D );
printf("│ arr3D[0] : %p\n", arr3D[0] );
printf("│ arr3D[0][0] : %p\n", arr3D[0][0] );
printf("│ arr3D[0][0][0]: %p -> %c\n", &(arr3D[0][0][0]), arr3D[0][0][0]);
printf("├─────────────────────────────────────────────────────────┤\n");
printf("│ arr3D : %p\n", arr3D );
printf("│ *(arr3D + 0) : %p\n", *(arr3D+0) );
printf("│ **(arr3D + 0) : %p\n", *(*(arr3D+0)) );
printf("│ ***(arr3D + 0) : %p -> %c\n", &(***(arr3D+0)), ***(arr3D+0));
printf("└─────────────────────────────────────────────────────────┘\n\n");
// Layer 1
printf("┌─────────────────── 3D 배열 구조 ────────────────────────┐\n");
printf("│ arr3D : %p\n", arr3D );
printf("│ arr3D[1] : %p\n", arr3D[1] );
printf("│ arr3D[1][0] : %p\n", arr3D[1][0] );
printf("│ arr3D[1][0][0]: %p -> %c\n", &(arr3D[1][0][0]), arr3D[1][0][0]);
printf("├─────────────────────────────────────────────────────────┤\n");
printf("│ arr3D : %p\n", arr3D );
printf("│ *(arr3D + 1) : %p\n", *(arr3D+1) );
printf("│ **(arr3D + 1) : %p\n", *(*(arr3D+1)) );
printf("│ ***(arr3D + 1) : %p -> %c\n", &(***(arr3D+1)), ***(arr3D+1));
printf("└─────────────────────────────────────────────────────────┘\n\n");
// Layer 2
printf("┌─────────────────── 3D 배열 구조 ────────────────────────┐\n");
printf("│ arr3D : %p\n", arr3D );
printf("│ arr3D[1] : %p\n", arr3D[1] );
printf("│ arr3D[1][1] : %p\n", arr3D[1][1] );
printf("│ arr3D[1][1][0]: %p -> %c\n", &(arr3D[1][1][0]), arr3D[1][1][0]);
printf("├─────────────────────────────────────────────────────────┤\n");
printf("│ arr3D : %p\n", arr3D);
printf("│ *(arr3D + 1) : %p\n", *(arr3D+1));
printf("│ *(*arr3D) + 1) : %p\n", *((*arr3D)+1));
printf("│ **(*arr3D) + 1) : %p -> %c\n", &(**((*arr3D)+1)), **(*arr3D)+1);
printf("└─────────────────────────────────────────────────────────┘\n\n");
return 0;
}

4. 함수와 다차원 배열
더보기
#include <stdio.h>
int main(void)
{
int arr_2d[4][4] = {
0,
};
//1
unsigned char ucSize = sizeof(arr_2d); // arr_2d 메모리 크기 Byte
unsigned char ucRow = sizeof(*arr_2d); // arr_2d[0] 1차원 크기 Byte
unsigned char ucCol = ucSize/ucRow; // arr_2d 메모리 크기 전체를 1차원 크기로 나누면 컬럼 개수
printf("%d %d %d\n", ucSize, ucRow, ucCol);
//2
printf(" arr_2d: %p %2d\n", arr_2d, sizeof(arr_2d)); //arr_2d[0][0] 의 포인터의 포인터
printf(" *arr_2d: %p %2d\n", *arr_2d, sizeof(*arr_2d)); //arr_2d[0][0] 의 포인터
printf("**arr_2d: %d %2d\n", **arr_2d, sizeof(**arr_2d)); //arr_2d[0][0]
return 0;
}
#include <stdio.h>
int change_Arr_2d(int *arr)
{
printf("%p\n", arr);
printf("입력하세요 >> ");
scanf("%d", arr + 0); // arr[0]
printf("입력하세요 >> ");
scanf("%d", arr + 1); // arr[1]
printf("입력하세요 >> ");
scanf("%d", arr + 2); // arr[2]
printf("입력하세요 >> ");
scanf("%d", arr + 3); // arr[3]
return 0;
}
int print_Arr_2d(int *arr_2d)
{
unsigned char ucSize = sizeof(arr_2d);
unsigned char ucRow = sizeof(*arr_2d);
unsigned char ucCol = ucSize/ucRow;
printf("%d %d %d\n", ucSize, ucRow, ucCol);
unsigned char cnt = 0;
for (size_t i = 0; i < 4; i++)
{
for (size_t j = 0; j < 4; j++)
{
printf("%d ", *(arr_2d+cnt));
// printf("%d ", (*arr_2d)[j]);
cnt+=1;
}
printf("\n");
}
return 0;
}
int main(void)
{
int arr_2d[4][4] = {
0,
};
//3
int *ptr = &(arr_2d[0][0]);
change_Arr_2d(*arr_2d);
//4
// print_Arr_2d(*arr_2d);
print_Arr_2d(ptr);
return 0;
}