This question already has answers here:
Using sizeof with a dynamically allocated array
(5 answers)
Closed 7 years ago.
I'm working on a C program that involves generating adjacency matrices of random graphs. Here is a snippet of the source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
int main()
{
int **A = create_matrix(4, 3);
destory_matrix(A);
return 0;
}
int** create_matrix(int size, int seed)
{
// Allocate space for matrix
int **A = malloc(size * size * sizeof(int));
for (int r = 0; r < size; r++) {
A[r] = malloc(size * sizeof(int));
}
// Fill entries
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
A[i][j] = seed * (i + 1) * (j + 1);
}
}
return A;
}
void destory_matrix(int **A)
{
int size = sizeof(A[0]) / sizeof(int);
for (int r = 0; r < size; r++) {
free(A[r])
}
free(A);
}
This portion of the code is responsible for creating the matrix (the create_matrix() function) and free'ing memory (destroy_matrix()). I'm looking at destroy_matrix(), and noticed that when a 4x4 matrix is passed in, the variable size evaluated to 2, rather than 4. Could anyone explain why this happens?
I think you have a basic misunderstanding of the sizeof operator. It can't, in general, be used to get the size of dynamically allocated compound objects. The sizeof operator returns to you the size based on the type of the operand. In your case, the type of the operand is int *. I guess you are running on a 64 bit system. So the sizeof any pointer is 8. Hence your size variable will always be 2 no matter the size of your matrix.
The sizeof operator applied to a pointer returns the size of the pointer type, not the size of any allocated memory it happens to point to.
This is one of the key differences between an array type and a pointer type in C (note: arrays can decay to pointers). sizeof applied to an statically specified array type (e.g. int foo[n];) will get you the size of the array in bytes.
Since your word size is probably 8 bytes (64-bit), the size of a pointer will be 8 bytes, and if sizeof(int) is 4 bytes (32-bits), you have 8 / 4 = 2;
You need to consider some other way to store the dimensions of your matrices if you need runtime-sized heap-allocated matrices, e.g. a struct that stores the dimensions and a pointer to the allocated memory. It would be better to avoid possible heap-fragmentation altogether, though.
Try this if you have C99:
int n = 4, m = 5;
int (*A)[n] = malloc(m * sizeof A[0]));
free(A);
This allocates an m length array of int[n] as a single block, so you can do size_t n = sizeof(A)/sizeof(A[0]); to get one dimension(n) but you'll need to store m if you want to iterate correctly.
Related
I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)
I'm playing with pointers and stumbled accross this problem. Like in this question I wanted a generic method signature for function foo, therefore I chose void * input as parameter. For testing reasons I casted the void pointer to an int ** pointer to use it like an 2D array.
#include <stdio.h>
#include <stdlib.h>
void * foo(void *input, size_t mySize)
{
for (size_t i = 0; i < mySize; ++i)
{
for (size_t j = 0; j < mySize; ++j)
{
((int **)input)[i*mySize][j] = 10*i+j;
}
}
return input;
}
int main(int argc, char const *argv[])
{
size_t const mySize = 10;
void * myMemory, * testPtr;
myMemory = malloc(mySize * mySize * sizeof(int));
testPtr = foo(myMemory, mySize);
free(testPtr);
return 0;
}
Now I thought that using the [] operator would be same as adding an int to the pointer, e.g. that ((int **)input[i][j] would be the same like `((int **)input)+i+j
But accessing the input array in foo segfaults and using gdb shows me
(gdb) p ((int **)input)[i][j]
Cannot access memory at address 0x0
(gdb) p ((int **)input)+i+j
$25 = (int **) 0x405260
so obviously there is a difference. And therefore I'm confused.
While arrays and pointers are similar, they are not the same.
An array - single or multi dimensional - depicts a continuous chunk of memory, containing a specific datatype. For exampleint arr [10] declares arr as 10 continuous ints in memory. int multi_arr[5][10] declares multi_arr as 5 arrays of 10 continuous ints in memory.
Furthermore, the name arr would be the base address of this array, and passing it to a function would be the same as passing &arr[0].
But this is where the similarities end. A multi dimensional array can't (technically) be cast to a pointer-to-a-pointer and then back again.
If arr above pointed to a block of ints, then dereferencing the first dimension of int ** ptr would lead you to a block of pointers toint. Dereferencing that would not take you deeper into that block, as a multi dimensional array would, rather it could point anywhere.
You allocated a one dimension array with mySize*mySize elements.
int** is an array of pointers to int, what you want is
int **array2d;
int *p;
array2D = malloc(ROWS * sizeof(int*) + ROWS * COLUMNS * sizeof(int));
p = (int*) &array2d[ROWS];
for (size_t i = 0; i < ROWS; ++i)
array2d[i] = &p[i * COLUMNS];
now array2d[row][column] can work.
Or, as already suggested, use a one dimension array and use the array[row * COLUMNS + column] formulae.
I'm trying to create a shared memory for IPC. I want to put a structure with dynamic 2D array in it into the shared memory. Here is the structure.
/* struct with 2 2D arrays. */
struct _test {
uint16_t **A;
uint16_t **B;
} test;
I know that a double pointer is not actually a 2D array and I should use a pointer to array like int (*ptr)[3], but the problem is that I can only get the size of the 2D array during runtime. So I have to declare the 2D array this way(at least what I know of).
Then I calculate the size of those two arrays in run time, say they both are 2x2 arrays, which takes 16 bytes(uint16_t is 2 byte). So I did this:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t size = 16; //size of two uint16_t 2D arrays.
key_t key;
key = ftok("dev/null", 1);
int s_shm_id = shmget(key, size, IPC_CREAT|0600); //get 16 bytes of shared memory.
test *shm = (test*)shmat(s_shm_id,(const void*)0,0); //attach it.
//I want pointers in this struct to point at shared memory.
test *ptr = malloc(sizeof(test));
//Array A starts at the beginning of shared memory.
ptr -> A = (uint16_t **)shm; //My main confusion is here. Is this right?
int i;
for(i=0; i<2; i++)
ptr->A[i] =(uint16_t *)((uint16_t *)ptr->A + i*2);
//Array B starts right after A.
ptr -> B = ptr -> A[i-1] + 2;
for(i=0; i<2; i++)
ptr -> B[i] = (uint16_t *)((uint16_t *)ptr->B + i*2);
}
I understand this is basically wrong, I got segfault, but how? What a pointer needs is an address to point at, since I have already created a space(using shmget), why can't I make a pointer to point at it? Thanks for any feed back in advance!
What you are after are "jagged" or "scattered" arrays, not "linear" arrays. A scattered 2D-array in fact is not one array, but 1+N arrays, with N being the dimension of the 2D-matrix you are after.
The code you show misses to allocated this 1 array inside "1+N".
Assuming you successfully allocated enough memory to hold two 2D arrays with dimension N of uint16_t, that is 2 * N*N * sizeof (uint16_t) bytes, then the code to prepare the access to this memory might look like this (error checking left out for readability):
void * p = ... /* Allocate memory here; does not necessarily needs to be SHM. */
uint16_t ** A = malloc(N * sizeof *A);
for (size_t i = 0; i < N; ++i)
{
A[i] = ((uint16_t*) p) + i*N;
}
uint16_t ** B = malloc(N * sizeof *B);
for (size_t i = N; i < 2*N; ++i)
{
B[i - N] = ((uint16_t*) p) + i*N;
}
/* Access A[0 .. N-1][0 .. N-1] and B[0 .. N-1][0 .. N-1] here ... */
Placing A and B inside a struct which in turn is allocated dynamically is left to you as an exercise.
Accessing the arrays' elements is done straight forward: A[0][0] accesses the 1st array's 1st row's 1st element.
For clarity the same code for NxM arrays
uint16_t ** A = malloc(N * sizeof *A);
for (size_t i = 0; i < N; ++i)
{
A[i] = ((uint16_t*) p) + i*M;
}
uint16_t ** B = malloc(N * sizeof *B);
for (size_t i = N; i < 2*N; ++i)
{
B[i - N] = ((uint16_t*) p) + i*M;
}
Does someone know how I can use dynamically allocated multi-dimensional arrays using C? Is that possible?
Since C99, C has 2D arrays with dynamical bounds. If you want to avoid that such beast are allocated on the stack (which you should), you can allocate them easily in one go as the following
double (*A)[n] = malloc(sizeof(double[n][n]));
and that's it. You can then easily use it as you are used for 2D arrays with something like A[i][j]. And don't forget that one at the end
free(A);
Randy Meyers wrote series of articles explaining variable length arrays (VLAs).
With dynamic allocation, using malloc:
int** x;
x = malloc(dimension1_max * sizeof(*x));
for (int i = 0; i < dimension1_max; i++) {
x[i] = malloc(dimension2_max * sizeof(x[0]));
}
//Writing values
x[0..(dimension1_max-1)][0..(dimension2_max-1)] = Value;
[...]
for (int i = 0; i < dimension1_max; i++) {
free(x[i]);
}
free(x);
This allocates an 2D array of size dimension1_max * dimension2_max. So, for example, if you want a 640*480 array (f.e. pixels of an image), use dimension1_max = 640, dimension2_max = 480. You can then access the array using x[d1][d2] where d1 = 0..639, d2 = 0..479.
But a search on SO or Google also reveals other possibilities, for example in this SO question
Note that your array won't allocate a contiguous region of memory (640*480 bytes) in that case which could give problems with functions that assume this. So to get the array satisfy the condition, replace the malloc block above with this:
int** x;
int* temp;
x = malloc(dimension1_max * sizeof(*x));
temp = malloc(dimension1_max * dimension2_max * sizeof(x[0]));
for (int i = 0; i < dimension1_max; i++) {
x[i] = temp + (i * dimension2_max);
}
[...]
free(temp);
free(x);
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 zero 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 initially contain anything. Note2: ary1[5] accesses memory in an undefined state (which may not even be accessible to you), so don't do it!
Multi-dimensional arrays are implemented as an array of arrays (of arrays (of ... ) ). So
float ary2[3][5];
declares an array of 3 one-dimensional arrays of 5 floating point numbers each. 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 (sec. A8.6.2 on page 216 of my K&R 2nd. ed.) but seems to be agnostic on padding.
Trying to go dynamic in more than one dimension
If you don't know the size of the array at compile time, you'll want to dynamically allocate the array. It is tempting to try
double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */
which should work if the compiler does not pad the allocation (stick extra space between the one-dimensional arrays). It might be safer to go with:
double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */
but either way the trick comes at dereferencing time. You can't write buf[i][j] because buf has the wrong type. Nor can you use
double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */
because the compiler expects hdl4 to be the address of an address of a double. Nor can you use double incomplete_ary4[][]; because this is an error;
So what can you do?
Do the row and column arithmetic yourself
Allocate and do the work in a function
Use an array of pointers (the mechanism qrdl is talking about)
Do the math yourself
Simply compute memory offset to each element like this:
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 */
}
}
Allocate and do the work in a function
Define a function that takes the needed size as an argument and proceed as 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 can not return it: all the work with the array must be done in the function you call of in functions that it calls.
An array of pointers
Consider this:
double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
hdl5[i] = malloc(5*sizeof(double))
/* Error checking */
}
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 the two-dimensional array notation to access this structure---hdl5[0][2] gets the middle element of the first row---but this is none-the-less a different kind of object than a two-dimensional array declared by double ary[3][5];.
This structure is more flexible then a two dimensional array (because the rows need not be the same length), but accessing it will generally be slower and it requires more memory (you need a place to hold the intermediate pointers).
Note that since I haven't setup any guards you'll have to keep track of the size of all the arrays yourself.
Arithmetic
c provides no support for vector, matrix or tensor math, you'll have to implement it yourself, or bring in a library.
Multiplication by a scaler and addition and subtraction of arrays of the same rank are easy: just loop over the elements and perform the operation as you go. Inner products are similarly straight forward.
Outer products mean more loops.
If you know the number of columns at compile time, it's 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 treat ap like any 2D array:
ap[i][j] = x;
When you're done you deallocate it as
free(ap);
If you don't know the number of columns at compile time, but you're working with a C99 compiler or a C2011 compiler that supports variable-length arrays, it's still pretty 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 don't know the number of columns at compile time and you're working with a version of C that doesn't support variable-length arrays, then you'll need to do something different. If you need all of the elements to be allocated in a contiguous chunk (like a regular array), then you can allocate the memory as a 1D array, and compute a 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 don't need the memory to be contiguous, you can follow a two-step 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 allocation was a two-step process, deallocation also needs to be a two-step process:
for (i = 0; i < cols; i++)
free(ap[i]);
free(ap);
malloc will do.
int rows = 20;
int cols = 20;
int *array;
array = malloc(rows * cols * sizeof(int));
Refer the below article for help:-
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.
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));
}
// 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];
}
Does someone know how I can use dynamically allocated multi-dimensional arrays using C? Is that possible?
Since C99, C has 2D arrays with dynamical bounds. If you want to avoid that such beast are allocated on the stack (which you should), you can allocate them easily in one go as the following
double (*A)[n] = malloc(sizeof(double[n][n]));
and that's it. You can then easily use it as you are used for 2D arrays with something like A[i][j]. And don't forget that one at the end
free(A);
Randy Meyers wrote series of articles explaining variable length arrays (VLAs).
With dynamic allocation, using malloc:
int** x;
x = malloc(dimension1_max * sizeof(*x));
for (int i = 0; i < dimension1_max; i++) {
x[i] = malloc(dimension2_max * sizeof(x[0]));
}
//Writing values
x[0..(dimension1_max-1)][0..(dimension2_max-1)] = Value;
[...]
for (int i = 0; i < dimension1_max; i++) {
free(x[i]);
}
free(x);
This allocates an 2D array of size dimension1_max * dimension2_max. So, for example, if you want a 640*480 array (f.e. pixels of an image), use dimension1_max = 640, dimension2_max = 480. You can then access the array using x[d1][d2] where d1 = 0..639, d2 = 0..479.
But a search on SO or Google also reveals other possibilities, for example in this SO question
Note that your array won't allocate a contiguous region of memory (640*480 bytes) in that case which could give problems with functions that assume this. So to get the array satisfy the condition, replace the malloc block above with this:
int** x;
int* temp;
x = malloc(dimension1_max * sizeof(*x));
temp = malloc(dimension1_max * dimension2_max * sizeof(x[0]));
for (int i = 0; i < dimension1_max; i++) {
x[i] = temp + (i * dimension2_max);
}
[...]
free(temp);
free(x);
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 zero 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 initially contain anything. Note2: ary1[5] accesses memory in an undefined state (which may not even be accessible to you), so don't do it!
Multi-dimensional arrays are implemented as an array of arrays (of arrays (of ... ) ). So
float ary2[3][5];
declares an array of 3 one-dimensional arrays of 5 floating point numbers each. 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 (sec. A8.6.2 on page 216 of my K&R 2nd. ed.) but seems to be agnostic on padding.
Trying to go dynamic in more than one dimension
If you don't know the size of the array at compile time, you'll want to dynamically allocate the array. It is tempting to try
double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */
which should work if the compiler does not pad the allocation (stick extra space between the one-dimensional arrays). It might be safer to go with:
double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */
but either way the trick comes at dereferencing time. You can't write buf[i][j] because buf has the wrong type. Nor can you use
double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */
because the compiler expects hdl4 to be the address of an address of a double. Nor can you use double incomplete_ary4[][]; because this is an error;
So what can you do?
Do the row and column arithmetic yourself
Allocate and do the work in a function
Use an array of pointers (the mechanism qrdl is talking about)
Do the math yourself
Simply compute memory offset to each element like this:
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 */
}
}
Allocate and do the work in a function
Define a function that takes the needed size as an argument and proceed as 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 can not return it: all the work with the array must be done in the function you call of in functions that it calls.
An array of pointers
Consider this:
double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
hdl5[i] = malloc(5*sizeof(double))
/* Error checking */
}
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 the two-dimensional array notation to access this structure---hdl5[0][2] gets the middle element of the first row---but this is none-the-less a different kind of object than a two-dimensional array declared by double ary[3][5];.
This structure is more flexible then a two dimensional array (because the rows need not be the same length), but accessing it will generally be slower and it requires more memory (you need a place to hold the intermediate pointers).
Note that since I haven't setup any guards you'll have to keep track of the size of all the arrays yourself.
Arithmetic
c provides no support for vector, matrix or tensor math, you'll have to implement it yourself, or bring in a library.
Multiplication by a scaler and addition and subtraction of arrays of the same rank are easy: just loop over the elements and perform the operation as you go. Inner products are similarly straight forward.
Outer products mean more loops.
If you know the number of columns at compile time, it's 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 treat ap like any 2D array:
ap[i][j] = x;
When you're done you deallocate it as
free(ap);
If you don't know the number of columns at compile time, but you're working with a C99 compiler or a C2011 compiler that supports variable-length arrays, it's still pretty 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 don't know the number of columns at compile time and you're working with a version of C that doesn't support variable-length arrays, then you'll need to do something different. If you need all of the elements to be allocated in a contiguous chunk (like a regular array), then you can allocate the memory as a 1D array, and compute a 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 don't need the memory to be contiguous, you can follow a two-step 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 allocation was a two-step process, deallocation also needs to be a two-step process:
for (i = 0; i < cols; i++)
free(ap[i]);
free(ap);
malloc will do.
int rows = 20;
int cols = 20;
int *array;
array = malloc(rows * cols * sizeof(int));
Refer the below article for help:-
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.
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));
}
// 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];
}