How to work with dynamic multidimensional arrays in C?

Does anyone know how I can use dynamically allocated multidimensional arrays using C? Is it possible?

+58
c arrays dynamic
May 27 '09 at 20:10
source share
10 answers

With dynamic allocation using 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); 

A 2D array of dimension1_max * dimension2_max size is highlighted here. For example, if you want an array of size 640 * 480 (fe pixels of an image), use dimension1_max = 640, dimension2_max = 480. Then you can access the array using x[d1][d2] , where d1 = 0..639, d2 = 0..479.

But a search in SO or Google also shows other possibilities, for example in this SO question

Please note that your array will not allocate an adjacent memory area (640 * 480 bytes) in this case, which may cause problems with functions that suggest this. So that the array satisfies the condition, replace the malloc block above with this:

 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); 
+74
May 27 '09 at 20:19
source share

Starting with C99, C has two-dimensional arrays with dynamic boundaries. If you want to avoid placing such animals on the stack (which should be done), you can easily select them at a time, as shown below.

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

what is it. Then you can easily use it, as you use for 2D arrays with something like A[i][j] . And don't forget that one at the end

 free(A); 

Randy Meyers has written a series of articles explaining variable-length arrays (VLAs) .

+73
09 Oct '12 at 18:16
source share

The basics

Arrays in c are declared and accessed using the [] operator. So that

  int ary1 [5]; > 

declares an array of 5 integers. Elements are numbered from scratch, so ary1 [0] is the first element, and ary1 [4] is the last element. Note1: There is no default initialization, so the memory occupied by the array may first contain something . ary1 [5] : ary1 [5] accesses memory in undefined state (which may not even be available to you), so do not do this!

Multidimensional arrays are implemented as an array of arrays (arrays (from ...)). So

  float ary2 [3] [5]; > 

declares an array of three one-dimensional arrays of 5 floating point numbers. Now ary2 [0] [0] is the first element of the first array, ary2 [0] [4] is the last element of the first array, and ary2 [2] [4] is the last element of the last array. The '89 standard requires this data to be contiguous (section A8.6.2 on page 216 of my K & R 2nd ed. Ed.), But it seems agnostic to populate.

Trying to go dynamically in more than one dimension

If you do not know the size of the array at compile time, you need to dynamically allocate the array. Tempting to try

  double * buf3; buf3 = malloc (3 * 5 * sizeof (double)); /*     */ > 

which should work if the compiler did not insert the selection (add extra space between one-dimensional arrays). It could be safer:

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

but in any case, the trick comes to dereferencing. You cannot write buf [i] [j] because buf is of the wrong type. You also cannot use

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

because the compiler expects hdl4 be the address of the double address. You also cannot use double incomplete_ary4 [] []; because it is a mistake;

So what can you do?

  • Do arithmetic of rows and columns yourself
  • Select and do work in function
  • Use an array of pointers (the qrdl mechanism says so)

Do it yourself math

Just calculate the memory offset for each item as follows:

  for (i = 0;  < 3; ++ i) {     (j = 0; j < 3; ++ j) {       buf3 [i * 5 + j] = someValue (i, j);/*                                                    */    } } > 

Select and do work in function

Define a function that takes the required size as an argument and acts like normal

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

Of course, in this case ary4 is a local variable, and you cannot return it: all work with the array must be performed in the function that you call in the functions that it .

Array of pointers

Consider this:

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

Now hdl5 points to an array of pointers, each of which points to an array of doubles. The cool bit is that you can use two-dimensional array notation to access this structure --- hdl5 [0] [2] gets the middle element of the first line --- but it's not less than an object than the two-dimensional array declared by double ary [3] [5]; .

This structure is more flexible than a two-dimensional array (because the lines do not have to be the same length), but access to it will usually be slower and require more memory (you need a place to store intermediate pointers).

Please note that since I did not configure any guards, you will have to independently monitor the size of all arrays.

Arithmetic

c does not support vector, matrix or tensor math, you will have to implement it yourself or bring a library.

Scaling up and adding and subtracting arrays of the same rank are easy: just iterate over the elements and perform the operation as you go. Domestic products are also straightforward.

External products mean more cycles.

+51
May 27 '09 at 21:34
source share

If you know the number of columns at compile time, this is pretty simple:

 #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 

You can consider ap like any 2D array:

 ap[i][j] = x; 

When you are done, you set him free

 free(ap); 

If you do not know the number of columns at compile time, but you are working with a C99 compiler or a C2011 compiler that supports variable length arrays, it is still quite simple:

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

If you do not know the number of columns at compile time and are working with a version of C that does not support variable length arrays, you need to do something else. If you need all the elements that will be selected in a continuous fragment (for example, a regular array), you can allocate memory as a 1D array and calculate the 1D offset:

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

If you do not want the memory to be continuous, you can follow the two-stage allocation method:

 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; 

Since distribution was a two-stage process, release should also be a two-stage process:

 for (i = 0; i < cols; i++) free(ap[i]); free(ap); 
+9
09 Oct '12 at 18:19
source share

malloc will do.

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

See the following article for help: -

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

0
09 Oct '12 at 16:18
source share

Here is the working code that defines the make_3d_array subroutine for placing a multidimensional 3D array with elements N1 , N2 and N3 in each dimension, and then fills 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); } 
0
Jul 31 '17 at 21:18
source share

// use a new one instead of malloc, since using malloc leads to memory leaks, enter the code here

  int **adj_list = new int*[rowsize]; for(int i = 0; i < rowsize; ++i) { adj_list[i] = new int[colsize]; } 
0
Jul 14 '19 at 5:56
source share

Unable to select all at once. Instead, create an array of pointers, and then create a memory for each pointer. 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 an array as int* array[50] and skip the first malloc, but the second set is needed to dynamically allocate the required storage.

You can hack a way to select it in one step, but this will require a custom search function, but writing it so that it always works can be annoying. An example would be L(arr,x,y,max_x) arr[(y)*(max_x) + (x)] , then malloc is a block of 50 * 50 int or any other and access using this macro L , for example

 #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 this is much more unpleasant if you do not know what you are doing with the preprocessor macro.

-one
Oct 09 '12 at 16:22
source share
 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)); } 
-2
09 Oct
source share

Why, colleagues, no one has discovered that in C there is no exact solution? but only in C ++ (more precisely, I mean that the above and other site solutions differ from real C-multidimensional arrays with: additional objects and, therefore, additional memory, etc.).

In C ++ you have to implement (just a few lines of code):

 typedef double T; class Matrix2D { public: Matrix2D(int, int); ~Matrix2D(); T* operator[](int); private: T* const memory; const int rows; const int cols; }; Matrix2D::Matrix2D(int r, int c) : rows(r), cols(c), memory(new T[r*c]) {} Matrix2D::~Matrix2D() { delete[] memory; } T* Matrix2D::operator[](int row) { return memory + cols*row;} 

This is all for those who use this code: a[i][j] .

But for exact resemblance to C-multidimensional arrays, this class ( Matrix2D ) does not have double pointer arithmetic, which will be used as follows: (*(a+i))[j] . It is not difficult: implement internal clsss "doublePointer" using arithmetic and dereference operators. But I would prefer to implement an iterator for these purposes (to go from line to line).

More than two dimensions? You just need inner classes that implement the corresponding operator[]...[] of (n-1) -size. Alas, the routine ..

-6
Feb 18 '16 at 15:46
source share



All Articles