티스토리 뷰

이차원배열을 어떻게 malloc하느냐는 질문을 받았는데, 쉽지 않은 주제네요.

이차원 배열을 함수 매개변수로 넘기는 방법을 먼저 살펴보겠습니다. C 언어에서 2차원 배열은 포인터의 배열이고 각 포인터는 COLS칸 배열의 주소를 가집니다. 여기서 ROWS, COLS는 상수를 나타내고 rows, cols는 변수일 수 있습니다. (참고)

void func(int array[ROWS][COLS]) { ...
void func_vla(int rows, int cols, int array[rows][cols]) { ...
void test(int array[][COLS], int rows) { ...
void test(int (* array)[COLS], int rows) { ...

첫번째는 상수 크기의 배열을 넘기는 방법입니다. 고정크기라면 이차원 배열로 넘길 수가 있는 거죠. 그리고 크기는 부르는 쪽이나 이 함수나 다 알고 있으니 따로 알려줄 필요가 없겠죠?

두 번째는 행과 열 크기를 다 모를 때입니다. 이 때 행과 열의 크기를 먼저 주고 이차원 배열을 넘기면 받는 쪽에서 그 배열을 받을 수 있습니다. 이 때도 이차원배열의 주소를 포인터(int**)로 넘지는 것은 동일합니다. 크기를 전달해 주어서 접근할 수 있게 해주는 것이지요.

세 번째와 네 번째는 같은 표현입니다. 네 번째는 int [COLS] 배열을 가리키는 포인터 array를 받겠다는 뜻입니다. 이것은 곧 COLS개 배열이 여러 개 연속해 나올 수있는 포인터가 되겠지요? 재미있는 것은 이 변수 array를 포인터 더하기 연산을 하면, 즉 array++하면 sizeof(int)*COLS 크기만큼 주소가 증가한다는 것입니다.

이렇게 하면 rows*COLS 이차원 배열을 매개변수로 넘길 수 있습니다. 그럼 이제 이차원 배열의 malloc을 살펴볼까요? 다음 글에서 잘 정리되어 있습니다. (코드는 그대로 가져오고 내용을 번역하면서 설명과 그림을 보충했습니다)

https://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/

 

How to dynamically allocate a 2D array in C? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

(1) 이차원 배열을 하나의 덩어리로 malloc하는 방법

    int r = 3, c = 4; 
    int *arr = (int *)malloc(r * c * sizeof(int)); 
  
    int i, j, count = 0; 
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         *(arr + i*c + j) = count++; 
  
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d ", *(arr + i*c + j)); 

이 방법은 한꺼번에 r*c개 메모리를 할당받은 다음 i, j번째 항을 찾을 때 포인터의 주소 계산을 하는 방법입니다. arr + i*c + j번째가 [i][j] 번째가 되는 거죠.

사실 위 코드의 for 루프는 다음과 같이 써도 됩니다. arr은 주소를 가지는 포인터의 포인터가 됩니다.

int* p = *arr;
for (i = 0; i < r*c; i++, p++)
    *p = count++;
for (i = 0, p = *arr; i < r*c; i++, p++)
    printf("%d ", *p);

(2) 포인터 배열을 이용하는 방법

    int r = 3, c = 4, i, j, count; 
  
    int *arr[r]; 
    for (i = 0; i < r; i++) 
         arr[i] = (int *)malloc(c * sizeof(int)); 
  
    // Note: arr[i][j] == *(*(arr+i)+j) 
    count = 0; 
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         arr[i][j] = count++; // 또는 *(*(arr+i)+j) = count++ 
  
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d ", arr[i][j]); 

함수에 매개변수로 보낼 때 이런 형태였죠? 포인터의 배열을 먼저 선언하고 각 포인터에 c개의 배열을 할당해 주는 방법입니다. 여기서 중요한 것은 각 행이 따로 malloc 되므로 연속된 메모리에 있다는 보장은 없다는 것입니다.

(3) 포인터의 포인터를 이용하는 방법

   int r = 3, c = 4, i, j, count; 
  
    int **arr = (int **)malloc(r * sizeof(int *)); 
    for (i=0; i<r; i++) 
         arr[i] = (int *)malloc(c * sizeof(int)); 
  
    // Note that arr[i][j] is same as *(*(arr+i)+j) 
    count = 0; 
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         arr[i][j] = count++;  // OR *(*(arr+i)+j) = count++ 
  
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d ", arr[i][j]); 

이중포인터는 주소의 주소를 가지는 포인터입니다. 이런 그림이 되겠네요. 사용은 (2)번 방법과 동일합니다.

(4) 진짜 이차원 배열처럼 동적할당하는 방법

우리는 이차원 배열이 (2)나 (3)처럼 여러 개의 힙 조각들로 흩어져 있기 보다는 한 덩어리로 모여 있는 것을 원합니다. C에서는 이차원 배열을 그렇게 할당해 줍니다. 그럼 진짜 이차원 배열처럼 동적할당하는 방법을 살펴보겠습니다. 가장 복잡하지만 배울 것이 많은 코드입니다. 실제 C 언어에서 이차원 배열이 할당되어 있는 것과 같은 모양으로 만들어줍니다.

    int r=3, c=4, len=0; 
    int *ptr, **arr; 
    int count = 0,i,j; 
  
    len = sizeof(int *) * r + sizeof(int) * c * r; 
    arr = (int **)malloc(len); // arr은 한 덩어리의 주소를 받아 int**로 저장했다.
  
    // ptr는 이차원 배열의 시작 부분을 가리킨다.
    ptr = (int *)(arr + r); 
  
    // arr의 행포인터들을 해당 위치를 가리키게 설정해 준다. 
    for(i = 0; i < r; i++) 
        arr[i] = (ptr + c * i); 
  
    // 이차원 배열에 차례로 증가하는 값을 넣는다.
    for (i = 0; i < r; i++) 
        for (j = 0; j < c; j++) 
            arr[i][j] = count++; // OR *(*(arr+i)+j) = count++ 
  
    for (i = 0; i < r; i++) {
        for (j = 0; j < c; j++) 
            printf("%d ", arr[i][j]); 
        printf("\n");
    }

실제 C 언어에서 이차원 배열을 할당하는 배치입니다. 제일 앞을 arr이 가리키고 있는 거구요, 앞에는 행포인터가 위치하고 있다고 보면 됩니다. 그러면 int arr[3][4];로 할당한 것과 같은 구조의 동적메모리 할당 배열이 됩니다.

'C 프로그래밍기초' 카테고리의 다른 글

C 포인터 (1) - 개요  (0) 2020.02.11
구조체란 무엇인가?  (0) 2020.02.11
C printf 요약매뉴얼  (0) 2020.01.08
C from Python - step 1  (0) 2019.12.25
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함