#include <stdio.h>
#include <malloc.h>
void Array1DProcess(int _arr[3]);
void Array2DProcess(int _arr2D[][3]);
void Pointer2DProcess(int** _pArr2D)
{
printf("_pArr2D Size: %d byte\n", sizeof(_pArr2D));
printf("*(_pArr2D + 0) Size: %d byte\n", sizeof(*(_pArr2D + 0)));
printf("*(*(_pArr2D + 0) + 0) Size: %d byte\n", sizeof(*(*(_pArr2D + 0) + 0)));
printf("_pArr2D[0]: %p\n", _pArr2D[0]);
printf("_pArr2D[1]: %p\n", _pArr2D[1]);
}
void main()
{
// 다차원 배열 (Multi-Dimensional Array)
// 2차원배열 [][]
// int arr [Row][Column] [행]과 [열] ([가로], [세로])
int arr[2][3] = { 11, 12, 13, 21, 22 };
// int arr[][]에서 두 번째 []에는 값이 비면 안됨.
// int arr[][3]이거 가능함. Row(행)이 비면 안됨.
// 3차원 배열은 [][][], x, y, z값
arr[1][1] = 55;
// 값을 출력할 때 { 11, }, { 21, 22, } 출력하면 11, 0 ,0, 21, 55, 0
for (int row = 0; row < 2; ++row)
{
for (int col = 0; col < 3; ++col)
{
printf("arr[%d][%d]: %d (%p)\n", row, col, arr[row][col], &arr[row][col]);
}
}
printf("arr Size: %d byte\n", sizeof(arr));
printf("arr[0] Size: %d byte\n", sizeof(arr[0]));
printf("arr[0][0] Size: %d byte\n", sizeof(arr[0][0]));
printf("\n");
printf("arr[0][4]: %d (%p)\n", arr[0][4], &arr[0][4]);
// arr[0][4] == arr[1][1]과 같은 주소, 출력값을 가지고 있음.
// 그 이유는 [0][4]는 [0][0]에서 4번 옮긴 값이고 [1][1]또한 4번 옮긴 값이기 때문이다.
printf("arr: %p\n", arr);
printf("arr[0]: %p\n", arr[0]);
printf("arr[1]: %p\n", arr[1]);
/////////////////////////////////////////////////////////////////////////////////////
printf("\n");
int arr1D[6] = { 11, 12, 13, 21, 22, 23 };
int* pLine0 = &arr1D[0]; // 11
int* pLine1 = &arr1D[3]; // 21
int* arr2D[2] = { pLine0, pLine1 };
int** pArr2D = arr2D;
printf("(pArr2D[1])[1]: %d\n", (pArr2D[1])[1]); // 아래와 같다.
printf("*(*(pArr2D + 1) + 1): %d\n", *(*(pArr2D + 1) + 1)); // 위와 같다
/////////////////////////////////////////////////////////////////////////////////////
printf("\n");
int testArr[3] = { 1, 2, 3 };
//int testArrEmpty[] = testArr;
Array1DProcess(testArr);
printf("testArr[0]: %d\n", testArr[0]);
printf("\n");
Array2DProcess(arr);
////////////////////////////////////////////////////////////////////////////////////
printf("\n");
//동적배열 (Dynamic Array)
int** pDArr2D = (int**)malloc(sizeof(int*) * 2);
for (int row = 0; row < 2; ++row)
pDArr2D[row] = (int*)malloc(sizeof(int) * 3);
for (int row = 0; row < 2; ++row)
for (int col = 0; col < 3; ++col)
pDArr2D[row][col] = ((row + 1) * 10) + (col + 1);
for (int row = 0; row < 2; ++row)
for (int col = 0; col < 3; ++col)
printf("*(*(pDArr2D + %d) + %d): %d\n", row, col, *(*(pDArr2D + row) + col));
printf("\n");
Pointer2DProcess(pDArr2D);
for (int row = 0; row < 2; ++row)
{
if (*(pDArr2D + row) != NULL)
{
free(*(pDArr2D + row));
*(pDArr2D + row) = NULL;
}
}
if (pDArr2D)
{
free(pDArr2D);
pDArr2D = NULL;
}
}
void Array1DProcess(int _arr[3])
{
printf("_arr Size: %d byte\n", sizeof(_arr));
_arr[0] = 100;
for (int i = 0; i < 3; ++i)
printf("_arr[%d]: %d\n", i, _arr[i]);
}
void Array2DProcess(int _arr2D[][3])
{
printf("_arr2D Size: %d byte\n", sizeof(_arr2D));
printf("_arr2D[0] Size: %d byte\n", sizeof(_arr2D[0]));
for (int row = 0; row < 2; ++row)
{
for (int col = 0; col < 4; ++col)
{
printf("_arr[%d][%d]: %d\n", row, col, _arr2D[row][col]);
}
}
}
오늘은 다차원 배열 중 2차원 배열에 대해 알아보겠습니다.
다차원배열은 [ ] 대괄호의 갯수에 따라 이름이 결정됩니다. [ ][ ] 면 2차원, [ ][ ][ ] 면 3차원이라고 생각하시면 됩니다. 그리고 다차원배열을 하기 전에 우리가 이해하기 쉽도록 그림으로 표시하는 다차원 배열과 실제 컴퓨터가 처리하는 다차원 배열의 차이를 그림판으로 설명드리겠습니다.
arr[2][3]이라는 2차원 배열에 대한 설명입니다. 위의 코드에서 이와 관련된 출력값을 다룬 코드를 살펴보겠습니다.
int arr[2][3] = { 11, 12, 13, 21, 22 }; // 없는 요소값은 자동 0으로 자동 초기화
arr[1][1] = 55; // 5번째 요소값을 55로 초기화
// 값을 출력할 때 { 11, }, { 21, 22, } 출력하면 11, 0 ,0, 21, 55, 0 // 없는 요소값은 0으로 자동 초기화
// row (행), col (열)로 col은 비워도 되지만, row는 빈칸을 넣으면 안된다.
for (int row = 0; row < 2; ++row) // 배열이 잘 출력되는지에 대한 반복문
{
for (int col = 0; col < 3; ++col)
{
printf("arr[%d][%d]: %d (%p)\n", row, col, arr[row][col], &arr[row][col]);
}
}
printf("arr Size: %d byte\n", sizeof(arr)); // arr[2][3] 배열 크기 출력문
printf("arr[0] Size: %d byte\n", sizeof(arr[0])); // arr[0] 배열 크기 출력문
printf("arr[0][0] Size: %d byte\n", sizeof(arr[0][0])); // arr[0][0] 배열 크기 출력문
printf("\n");
printf("arr[0][4]: %d (%p)\n", arr[0][4], &arr[0][4]); // arr[0][4]의 값 출력문
여기서 배열의 크기에 대한 설명, 출력할 배열의 col값보다 높은 숫자를 넣어도 가능한 이유 두 가지를 설명하겠습니다.
- arr[2][3] 배열 크기는 int 자료형의 기본 크기인 4byte가 6개 요소가 존재하여 24 byte가 출력됩니다.
- arr[0] 배열 크기는 arr[0][0] ~ arr[0][2]까지의 크기로 4byte에 3개 요소가 존재하여 12 byte가 출력됩니다.
- arr[0][0] 배열 크기는 arr배열의 첫 번째 요소에 대한 크기입니다. 따라서 4 byte가 출력됩니다.
- arr[0][4]는 arr[2][3]에서 col(열)의 값이 넘어버리는 상황입니다. 그러나, 오류가 나오지않고 5번째 요소인 arr[1][1]의 값, 55가 출력됩니다. 그 이유는 그림판에서의 예시를 보시면 이해하기 쉽습니다. 우리가 흔히 행과 열로 표기하는 2차원 배열을 실제 컴퓨터에서는 1행에 모든 열로 나열하는 방식으로 다룹니다. 그에 따라 5번째 요소인 [1][1]의 주소와 값을 가지며 출력됩니다.
<포인터 배열> (Pointer Array)
int arr1D[6] = { 11, 12, 13, 21, 22, 23 }; // arr1D라는 6크기의 1차원 배열
int* pLine0 = &arr1D[0]; // 11 // arr1D의 첫 번째 주소값을 가지는 pLine0 포인터 변수
int* pLine1 = &arr1D[3]; // 21 // arr1D의 네 번째 주소값을 가지는 pLine1 포인터 변수
int* arr2D[2] = { pLine0, pLine1 }; // pLine0, 1 포인터 변수를 배열로 가진 arr2D라는 포인터 배열
int** pArr2D = arr2D; // arr2D의 첫 번째 요소 pLine0 이중 포인터 pArr2D
- arr2D[2] 포인터 배열에 pLine0, pLine1를 넣음.
- Arr2D 이중 포인터에는 arr2D의 첫 번째 요소값 pLine0을 부여합니다. 여기서 이중 포인터는 2차원 배열에서 사용됩니다.
printf("(pArr2D[1])[1]: %d\n", (pArr2D[1])[1]); // pArr2D[1][1]: 22
printf("*(*(pArr2D + 1) + 1): %d\n", *(*(pArr2D + 1) + 1)); // *(*(pArr2D + 1) + 1): 22
주석은 출력값입니다.
- pArr2D[1]의 [1]은 arr2D[1]을 가리키며 pLine1의 arr1D[3] 21 다음 22가 값으로 출력
- *(pArr2D + 1) + 1에서 *(pArr2D+1)은 arr2D[1]의 위치값과 같습니다. 때문에 pLine1입니다. 거기다 +1의 포인터, 위치값이기 때문에 arr2D[1][1]이 됩니다. 그래서 출력값은 22가 됩니다.
void main()
{
int testArr[3] = { 1, 2, 3 }; // 3크기를 가진 1차원 배열 testArr 배열
Array1DProcess(testArr); // Array1DProcess함수의 매개변수에 testArr 배열 대입
printf("testArr[0]: %d\n", testArr[0]); // testArr[0]: 100
}
void Array1DProcess(int _arr[3]) // 3크기를 가진 1차원 배열 _arr을 매개변수로 삼은 함수 (포인터)
{
printf("_arr Size: %d byte\n", sizeof(_arr)); // _arr Size: 8 byte
_arr[0] = 100; // _arr 배열 첫 번째 요소에 100으로 초기화;
for (int i = 0; i < 3; ++i) // 반복문
printf("_arr[%d]: %d\n", i, _arr[i]); // _arr[0]: 100 _arr[1]: 2 _arr[2]: 3
}
매크로를 이용하여 Array1DProcess 함수를 이용한 코드입니다. 관련 항목들 정리하겠습니다.
- 함수의 매개변수가 배열이라면, 그 매개변수는 포인터로 치환됩니다. 그래서 sizeof를 한다면 8byte입니다.
- 첫 번째 요소의 값을 100으로 초기화했기 때문에 testArr[0]: 100, _arr[0]: 100, _arr[1]: 2, _arr[2]: 3이 출력됩니다.
<동적 배열> (Dynamic Array)
#include <malloc.h>
void main()
{
int** pDArr2D = (int**)malloc(sizeof(int*) * 2); //2차원 배열의 pDArr2D 크기 설정
for (int row = 0; row < 2; ++row) // 2차원 배열의 각 행에 int * 3의 메모리를 할당
pDArr2D[row] = (int*)malloc(sizeof(int) * 3);
for (int row = 0; row < 2; ++row) // 행 2줄
for (int col = 0; col < 3; ++col) // 열 3줄
pDArr2D[row][col] = ((row + 1) * 10) + (col + 1); // 배열에 값 할당 행번호 + 1 * 10 + 열번호 + 1
for (int row = 0; row < 2; ++row) // 배열의 모든 요소를 출력. *(*(pDArr2D + row) + col) = pDArr2D[row][col]
for (int col = 0; col < 3; ++col)
printf("*(*(pDArr2D + %d) + %d): %d\n", row, col, *(*(pDArr2D + row) + col));
printf("\n");
Pointer2DProcess(pDArr2D); // pDArr2D 매개 포인터 변수를 가진 2DProcess 함수
for (int row = 0; row < 2; ++row) // 행 2줄
{
if (*(pDArr2D + row) != NULL) // pDArr2D에서 row만큼 떨어진 위치의 포인터 pDArr2D[row]
{ // NULL이 아니라면
free(*(pDArr2D + row)); // pDArr2D + row 포인터의 동적 할당된 메모리를 해제
*(pDArr2D + row) = NULL; // pDArr2D + row 메모리 해제 후 NULL로 유효하지 않은 상태
}
}
if (pDArr2D) // pDArr2D라면
{
free(pDArr2D); // pDArr2D에 동적 할당된 메모리를 해제
pDArr2D = NULL; // pDArr2D 메모리 해제 후 NULL로 유효하지 않은 상태
}
}
void Array2DProcess(int _arr2D[][3]) // Array2DProcess 함수 int_arr2D[ ][3] 2차원 배열 매개 변수
{
printf("_arr2D Size: %d byte\n", sizeof(_arr2D)); //_arr2D Size: 12byte (int byte * 3)
printf("_arr2D[0] Size: %d byte\n", sizeof(_arr2D[0])); //_arr2D[0] Size: 12byte (int byte * 3)
for (int row = 0; row < 2; ++row) // 행 2줄
{
for (int col = 0; col < 4; ++col) // 열 4줄
{
printf("_arr[%d][%d]: %d\n", row, col, _arr2D[row][col]); // _arr[0~1][0~3]: 값
}
}
}
위의 코드 중 Array2DProcess 함수에서 _arr2D Size와 _arr2D[0] Size가 같은 이유는 지난 번 배열에서 그림판으로 설명했던 것이 적용되는데 _arr2D[ ][ ]은 행이 0으로 처리됩니다. 즉 3개의 요소를 가지는 배열이라는 뜻이기 때문에 전체 size값은 int의 4byte에 * 3를 하여 12byte가 되고, _arr2D[0]은 한 줄에 포함된 모든 요소들의 크기 합을 나타냅니다. 그래서 똑같이 12byte가 출력됩니다.
끝
'프로그래밍 C언어' 카테고리의 다른 글
큐 (Queue) (0) | 2024.08.21 |
---|---|
스택 (Stack) (0) | 2024.08.21 |
상수 열거형 (Enumeration) (0) | 2024.08.20 |
공용체 (Union) (0) | 2024.08.20 |
구조체 (Structure) (0) | 2024.08.20 |