Nice programing

C에서 동적 다차원 배열을 어떻게 사용합니까?

nicepro 2020. 12. 9. 21:47
반응형

C에서 동적 다차원 배열을 어떻게 사용합니까?


누군가 C를 사용하여 동적으로 할당 된 다차원 배열을 사용하는 방법을 알고 있습니까? 가능합니까?


malloc을 사용하는 동적 할당 :

int** x;

x = malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = malloc(dimension2_max * sizeof(int));
}

[...]

for (int i = 0; i < dimension1_max; i++) {
  free(x[i]);
}
free(x);

이것은 dimension1_max* 크기의 2D 배열을 할당합니다 dimension2_max. 예를 들어, 640 * 480 배열 (이미지의 fe 픽셀)을 원하면 dimension1_max= 640, dimension2_max= 480을 사용합니다. 그런 다음 x[d1][d2]where d1= 0..639, d2= 0..479를 사용하여 배열에 액세스 할 수 있습니다 .

그러나 SO 또는 Google에서 검색 하면이 SO 질문과 같이 다른 가능성도 드러납니다.

배열은이를 가정하는 함수에 문제를 일으킬 수있는 연속적인 메모리 영역 (640 * 480 바이트)을 할당하지 않습니다. 따라서 배열이 조건을 충족 시키려면 위의 malloc 블록을 다음으로 바꿉니다.

int** x;
int* temp;

x = malloc(dimension1_max * sizeof(int*));
temp = malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = temp + (i * dimension2_max);
}

[...]

free(temp);
free(x);

C99부터 C에는 동적 경계가있는 2D 배열이 있습니다. 이러한 짐승이 스택에 할당되는 것을 피하려면 (필요한 경우) 다음과 같이 한 번에 쉽게 할당 할 수 있습니다.

double (*A)[n] = malloc(sizeof(double[n][n]));

그리고 그게 다야. 그런 다음 .NET과 같은 2D 배열에 사용되므로 쉽게 사용할 수 있습니다 A[i][j]. 그리고 마지막에 하나를 잊지 마세요

free(A);

Randy Meyers는 VLA ( 가변 길이 배열)를 설명하는 일련의 기사를 작성했습니다 .


기초

c의 배열은 []연산자를 사용하여 선언되고 액세스됩니다 . 그래서

int ary1[5];

5 개의 정수 배열을 선언합니다. 요소는 0부터 번호가 매겨져 ary1[0]첫 번째 요소이고 ary1[4]마지막 요소입니다. 주 : 메모리가 처음에 포함 할 수 있습니다 배열에 의해 점령 때문에, 디폴트의 초기화가 없다 아무것도 . Note2 : ary1[5]정의되지 않은 상태 (사용자가 액세스 할 수 없을 수도 있음)의 메모리에 액세스하므로 그렇게하지 마십시오!

다차원 배열은 (배열의 (...)) 배열의 배열로 구현됩니다. 그래서

float ary2[3][5];

각각 5 개의 부동 소수점 숫자로 구성된 3 개의 1 차원 배열의 배열을 선언합니다. 이제 ary2[0][0]제 배열의 첫 번째 요소이며, ary2[0][4]첫 번째 어레이의 마지막 요소이고, ary2[2][4]마지막 배열의 마지막 요소이다. '89 표준에서는이 데이터가 연속적이어야하지만 (K & R 2nd. 216 페이지의 A8.6.2 섹션) 패딩에 대해 불가지론적인 것 같습니다.

하나 이상의 차원에서 역동적으로 나아가려고

컴파일 타임에 배열의 크기를 모르는 경우 배열을 동적으로 할당하고 싶을 것입니다. 시도하고 싶은 유혹

double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */

컴파일러가 할당을 채우지 않으면 작동합니다 (1 차원 배열 사이에 추가 공간을 고정). 다음을 사용하는 것이 더 안전 할 수 있습니다.

double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */

하지만 어느 쪽이든 비 참조 시간에 트릭이 발생합니다. 당신은 쓸 수 buf[i][j]있기 때문에 buf잘못된 유형이 있습니다. 당신은 사용할 수 없습니다

double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */

컴파일러는 hdl4double 주소의 주소를 예상 하기 때문 입니다. double incomplete_ary4[][];이것은 오류이기 때문에 사용할 수 없습니다.

그래서 당신은 무엇을 할 수 있습니까?

  • 행 및 열 산술을 직접 수행하십시오.
  • 함수에서 작업을 할당하고 수행
  • 포인터 배열 사용 (qrdl이 말하는 메커니즘)

직접 수학

다음과 같이 각 요소에 대한 메모리 오프셋을 계산하기 만하면됩니다.

  for (i=0; i<3; ++i){
     for(j=0; j<3; ++j){
        buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                             padding in this case */
     }
  }

함수에서 작업을 할당하고 수행

필요한 크기를 인수로 사용하고 정상적으로 진행하는 함수를 정의합니다.

void dary(int x, int y){
  double ary4[x][y];
  ary4[2][3] = 5;
}

물론,이 경우 ary4지역 변수이며, 당신이 그것을 반환 할 수 없습니다 : 배열로 모든 작업은 그 기능에의 호출 함수에서 수행해야합니다 그것을 호출합니다.

포인터 배열

이걸 고려하세요:

double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
   hdl5[i] = malloc(5*sizeof(double))
   /* Error checking */
}

이제 hdl5각각 double의 배열을 가리키는 포인터 배열을 가리 킵니다. 멋진 부분은 2 차원 배열 표기법을 사용하여이 구조에 액세스 할 수 있다는 것입니다 .-- hdl5[0][2]첫 번째 행의 중간 요소를 가져옵니다-그러나 이것은 그럼에도 불구하고 2 차원과 다른 종류의 객체입니다. 에서 선언 한 배열 double ary[3][5];입니다.

이 구조는 2 차원 배열보다 더 유연하지만 (행의 길이가 같을 필요가 없기 때문에) 일반적으로 액세스 속도가 느려지고 더 많은 메모리가 필요합니다 (중간 포인터를 보관할 장소가 필요함).

가드를 설정하지 않았으므로 모든 어레이의 크기를 직접 추적해야합니다.

산수

c는 벡터, 행렬 또는 텐서 수학을 지원하지 않으므로 직접 구현하거나 라이브러리를 가져와야합니다.

스케일러에 의한 곱셈과 같은 순위의 배열을 더하고 빼는 것은 쉽습니다. 요소를 반복하고 진행하면서 연산을 수행하기 만하면됩니다. 내부 제품도 마찬가지로 간단합니다.

외부 제품은 더 많은 루프를 의미합니다.


컴파일 시간에 열 수를 알고 있다면 매우 간단합니다.

#define COLS ...
...
size_t rows;
// get number of rows
T (*ap)[COLS] = malloc(sizeof *ap * rows); // ap is a *pointer to an array* of T

ap2D 배열처럼 취급 할 수 있습니다 .

ap[i][j] = x;

완료되면 할당을 취소합니다.

free(ap);

컴파일 타임에 열 수를 모르지만 가변 길이 배열을 지원하는 C99 컴파일러 또는 C2011 컴파일러로 작업하는 경우 여전히 매우 간단합니다.

size_t rows;
size_t cols;
// get rows and cols
T (*ap)[cols] = malloc(sizeof *ap * rows);
...
ap[i][j] = x;
...
free(ap);

컴파일 타임에 열 수를 모르고 가변 길이 배열을 지원하지 않는 C 버전으로 작업하는 경우 다른 작업을 수행해야합니다. 모든 요소를 ​​연속적인 청크 (일반 배열과 같이)에 할당해야하는 경우 메모리를 1D 배열로 할당하고 1D 오프셋을 계산할 수 있습니다.

size_t rows, cols;
// get rows and columns
T *ap = malloc(sizeof *ap * rows * cols);
...
ap[i * rows + j] = x;
...
free(ap);

연속 될 메모리가 필요하지 않은 경우 2 단계 할당 방법을 따를 수 있습니다.

size_t rows, cols;
// get rows and cols
T **ap = malloc(sizeof *ap * rows);
if (ap)
{
  size_t i = 0;
  for (i = 0; i < cols; i++)
  {
    ap[i] = malloc(sizeof *ap[i] * cols);
  }
}

ap[i][j] = x;

할당은 2 단계 프로세스이므로 할당 해제도 2 단계 프로세스 여야합니다.

for (i = 0; i < cols; i++)
  free(ap[i]);
free(ap);

malloc이 할 것입니다.

 int rows = 20;
 int cols = 20;
 int *array;

  array = malloc(rows * cols * sizeof(int));

도움이 필요하면 아래 문서를 참조하십시오.

http://courses.cs.vt.edu/~cs2704/spring00/mcquain/Notes/4up/Managing2DArrays.pdf


Here is working code that defines a subroutine make_3d_array to allocate a multidimensional 3D array with N1, N2 and N3 elements in each dimension, and then populates it with random numbers. You can use the notation A[i][j][k] to access its elements.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


// Method to allocate a 2D array of floats
float*** make_3d_array(int nx, int ny, int nz) {
    float*** arr;
    int i,j;

    arr = (float ***) malloc(nx*sizeof(float**));

    for (i = 0; i < nx; i++) {
        arr[i] = (float **) malloc(ny*sizeof(float*));

        for(j = 0; j < ny; j++) {
            arr[i][j] = (float *) malloc(nz * sizeof(float));
        }
    }

    return arr;
} 



int main(int argc, char *argv[])
{
    int i, j, k;
    size_t N1=10,N2=20,N3=5;

    // allocates 3D array
    float ***ran = make_3d_array(N1, N2, N3);

    // initialize pseudo-random number generator
    srand(time(NULL)); 

    // populates the array with random numbers
    for (i = 0; i < N1; i++){
        for (j=0; j<N2; j++) {
            for (k=0; k<N3; k++) {
                ran[i][j][k] = ((float)rand()/(float)(RAND_MAX));
            }
        }
   }

    // prints values
    for (i=0; i<N1; i++) {
        for (j=0; j<N2; j++) {
            for (k=0; k<N3; k++) {
                printf("A[%d][%d][%d] = %f \n", i,j,k,ran[i][j][k]);
            }
        }
    }

    free(ran);
}

There's no way to allocate the whole thing in one go. Instead, create an array of pointers, then, for each pointer, create the memory for it. For example:

int** array;
array = (int**)malloc(sizeof(int*) * 50);
for(int i = 0; i < 50; i++)
    array[i] = (int*)malloc(sizeof(int) * 50);

Of course, you can also declare the array as int* array[50] and skip the first malloc, but the second set is needed in order to dynamically allocate the required storage.

It is possible to hack a way to allocate it in a single step, but it would require a custom lookup function, but writing that in such a way that it will always work can be annoying. An example could be L(arr,x,y,max_x) arr[(y)*(max_x) + (x)], then malloc a block of 50*50 ints or whatever and access using that L macro, e.g.

#define L(arr,x,y,max_x) arr[(y)*(max_x) + (x)]

int dim_x = 50;
int dim_y = 50;

int* array = malloc(dim_x*dim_y*sizeof(int));

int foo = L(array, 4, 6, dim_x);

But that's much nastier unless you know the effects of what you're doing with the preprocessor macro.


// use new instead of malloc as using malloc leads to memory leaks `enter code here

    int **adj_list = new int*[rowsize];       
    for(int i = 0; i < rowsize; ++i)    
    {

        adj_list[i] = new int[colsize];

    }

int rows, columns;
/* initialize rows and columns to the desired value */

    arr = (int**)malloc(rows*sizeof(int*));
        for(i=0;i<rows;i++)
        {
            arr[i] = (int*)malloc(cols*sizeof(int));
        }

참고URL : https://stackoverflow.com/questions/917783/how-do-i-work-with-dynamic-multi-dimensional-arrays-in-c

반응형