[ 다차원 배열 ]

 

다차원 배열이란 ?

2차원 이상의 배열을 의미하는 것이다. 2차원배열, 3차원배열 등등

 

2차원 배열 선언과 동시에 초기화

int main(void)

{

 //요소 전체 초기화

 int buila[3][3] = { 

                            { 1, 2, 3 },                          1  2  3

        { 4, 5, 6 },            =>           4  5  6

        { 7, 8, 9 }                           7  8  9

     };

 

//일부 요소만 초기화, 이런경우 부족한부분은 0으로 채워진다.

int buila2[3][3] = {

{ 1 },                                1  0  0

{ 4, 6 },              =>           4  6  0

{ 7, 8, 9}                           7  8  9

      };

 

//1차원 배열 초기화 형태를 취하는경우, 초기화 리스트의 수가 배열요소의 수보다 적은경우에는 나머지 요소들은 0으로 초기화 된다.                 

1  2  3

int buila3[3][3] = { 1, 2, 3, 4, 5, 6, 7 };   =>          4  5  6

7  0  0

 

//배열의 크기를 알려주지 않고 초기화하기, 최소한 한개의 인덱스는 가지고 있어야한다. 첫번째 인덱스만 생략 가능하다. 2 x 4 or 4 x 2

 

int buila4[][4]   = { 1, 2, 3, 4, 5, 6, 7,  8 }; 

 

....

}

 

 

2차원 배열 이름의 포인터 타입 

 


 

위의 코드에서 보듯이

 

a[0] == a는 같다,  

a[0] == a[0][0]은 같다. a[0]은 a[0][0]을 가르킨다.

a[1] == a[1][0]은 같다. a[1]은 a[1][0]을 가르킨다.

a[2] == a[2][0]은 같다. a[2]은 a[2][0]을 가르킨다.  

 

 

─────────────────────────────────────────────

2차원 배열 이름을 이용한 포인터 연산  

 


 

위의 코드를 보면

 

a는    a[0][0]을 가르킨다.

a+1는 a[1][0]을 가르킨다.

a+2는 a[2][0]을 가르킨다. 

 

즉!

a    == a[0] 같다. a[0]은 a[0][0]을 가르킨다.

a+1 == a[1] 같다. a[1]은 a[1][0]을 가르킨다.

a+2 == a[2] 같다. a[2]은 a[2][0]을 가르킨다. 

 

"2차원 배열 이름은 포인터 연산 시 행 단위로 이동한다." 

"int a[3][2];  // (4바이트 * 2) 행단위로 차이가 난다 "

"int a[2][3];  // (4바이트 * 3) 행단위로 차이가 난다."

 

자 이제 위의 내용을 정리해보면 배열이름의 포인터 타입이 나온다. 

 

int arr[2][4]; => int (*pArr)[4];  

 

읽어보면,

int형 변수를 가르키고 포인터연산시 4칸씩 이동하는 pArr포인터

 

위에 [4]는 포인터 연산에 따른 증가 혹은 감소의 폭을 말한다.

포인터 연산에 의해 값이 1 증가 및 감소 될경우 4칸씩(행단위 이동이니까) 이동하는 포인터라는 것

pArr이 가리키는 대상이 int형 데이터이므로 (4 * 4) 이동하게 될것이다.

 

 

 

 

─────────────────────────────────────────────

함수 인자로 다차원 배열 전달하기 

 

 

[코드] 



 

[결과]


 

위의 코드는?

int (*ptr)[4] 포인터 타입으로 받을수있는 서로다른 2차원배열의 요소값을 다중for문을 이용해서 출력하는 예제 입니다. 

 

여기서 잠깐!!  

int (*pArr)[4];    //int형 변수를 요소로 지니고 포인터 연산시 4칸씩 이동하는 2차원 배열을

                          가리키는 포인터

int* pArr[4];      //int형 변수의 주소값 4개를 저장할 수 있는 배열

 

 

 

 int* arr1[5];               =>     int** p1;          //1차원 배열이니까 포인터에 포인터선언

 int* arr2[3][5];          =>     int* (*p2)[5];   //2차원 배열이니까 (*p2)선언 및 포인터 연산시 [5]칸

 int** arr3[5];             =>     int*** p3;

 int*** arr4[3][5]        =>     int*** (*pArr)[5];

 

해깔린다. 명백히 해놓자.

  

[ 다중 포인터 ]

 

다중포인터란?

포인터의 포인터 혹은 더블포인터라 불리는 포인터이다.

 

ex ) int ** pP;

 

포인터는 기본적으로 그 대상 변수의 양(사이즈)이 많거나, 함수안에서 사용하는 목적으로 만듭니다.

(어디까지나 나의 생각 기준 입니다.)

 

그럼 다중포인터는 왜 필요해서 쓰는걸까?  

 

예를 들어봅시다.

void malloc_Func(int *x)

{

    x = (int*)malloc(sizeof(int)*100);

}

 

void main()

{

    int *p = NULL;

    malloc_Func(p); //문제점!!

}

 

위의 코드는 함수에서, 호출한 쪽의 포인터에 메모리 할당을 하기 위해서 간단하게 코딩한것입니다.

 

언뜻보기엔 문제가 없어 보이지만, 이 코드에는 문제가 있습니다.

 

간단하게 정리하자면, int* p 와  int * x 는 각각의 포인터 변수이고, 매개변수로 p가 전달됨으로써

x는 p가 가르키는 (NULL)을 똑같이 가르킬 뿐이지, 각각의 포인터라는 뜻입니다.

위의 코드대로 x에 메모리 할당을 해봤자, 각각의 포인터 변수이니까 p는 할당이 안되는것이죠

 

즉 같은 곳을 가르키는 전혀다른 포인터 변수 라는것입니다. 이걸 그냥 복사본이라고 하죠

int *x 는 int * p 하고는 상관이 없는 것입니다.

 

그럼 왜 복사본이 되는것일까?

이유는 간단합니다. 포인터 변수에다가 포인터 변수를 담았으니, 주소값이 대입이 이루어집니다.

변수는 다르지만, 같은것을 가르키게 되는것이죠. Call-By-Value

 

그럼 이문제를 어떻게 해결하면 좋을까요?

우리는 int * p 를 x 가 참조하여 x 를 통해 p를 변경하면 가능합니다.

쉽게 말해 x가 p를 가르키게 만들면, x에다가 할당하면 p가 할당이 되는 것입니다. x가 p의 주소값을 가르키기 때문에 x에다가 동적 할당 하면, 결국 p의 주소에 메모리가 할당 되는것이죠

 

자 그럼 더블 포인터에 의한 Call-By-Reference 바꿔보죠

void malloc_Func(int **x) // main()의 p 변수 자체를 가리키는, "p에 대한 포인터".

{

    *x = (int*)malloc(sizeof(int)*100); // *x가 p와 같음. main()의 p 가 새 메모리를 가리키게 함.

}

void main()

{

     int *p = NULL;

     malloc_Func(p);

}

 

위의 코드에서 더블포인터를 사용해서 메모리 할당을 하였습니다.

왜냐? p 변수 자체를 가르키는 포인터를 정의 하기위해서 더블포인터를 사용한것이죠.

이렇게 되면, 매개변수 x는 p가 가르키는 (NULL)을 가르키게 되는게 아니라,

포인터변수 p를 가르키게 되겠죠.

즉 매개변수 x로 p를 바꿀수있게 되는것입니다.(*x == p) 가 되는것이죠. 

 

그럼 main함수에 있는 포인터 p는 함수에서 할당된 새메모리를 가르키게 되는것입니다.

더블포인터를 사용해서 깔끔하게 수정이 됐습니다. 

 

다중,더블포인트는 쓰이는데는 여러가지가 있습니다.

하지만, 쓰이는곳이 조금씩 틀릴뿐이지, 여기서 크게 의미가 바뀌는 부분은 없습니다.

    

'0x0001 > C, C++' 카테고리의 다른 글

[C언어] 메모리 관리와 동적할당  (0) 2019.02.08
[C언어] 함수 포인터, void형 포인터  (0) 2019.02.07
[C언어] const 키워드  (0) 2019.02.07
[C언어] extern "C"  (0) 2019.02.07
[C언어] 재귀적 함수, 가변인자 함수  (0) 2019.02.07

+ Recent posts