Allocate 2D Array in C (not array of pointers) in Heap - c

I have a simple question, but the answer seems to be very difficult to find:
How do I create a true 2D array in C (not C++), dynamically sized (size not known at compile time), not an array of pointers, on the heap, so that I can put that allocation into a separate function and return the allocated array, without receiving any warnings from gcc -Wall?
I've found numerous other questions here on SO and in other forums, but the answers all had some flaw:
I saw many answers, which showed how to initialize an array of pointers, which according to some comments can lead to memory fragmentation and needs a loop to be freed when not used anymore.
I don't want to only have a predefined size of the array, but want to use it in some loops, creating arrays of many sizes.
I don't want the values in the array to be predefined either, they're calculated while the program is running.
I read about the layout in the memory, which can be different when using some methods of creating the array, while one can still use the array like this: a[y][x]. I want my array to have the memory layout of a true 2D array as well.
What is the right way to achieve allocation of such a true 2D array?
EDIT#1:
The return type of the allocation method can be a pointer to the allocated array.

You don't need a special function. Just do it like this
double (*A)[n][m] = malloc(sizeof *A);
As of C99, here n and m can be any positive integer expressions you want.
Such a thing is a pointer to a VLA, variable length array.

I know that this is not the perfect answer; but I hope it will be helpful.
#include <stdio.h>
#include <stdlib.h>
#define ELEM(myArr,X,Y) (myArr->arr[myArr->cols * X + Y])
#define FREE_MY_ARR(myArr) \
if(myArr){if(myArr->arr) free(myArr->arr); free(myArr);}
typedef struct myArr
{
int rows , cols;
int * arr;
} myArr;
myArr * create_my_arr(int rows , int cols)
{
myArr * my_arr = malloc(sizeof(myArr));
my_arr->rows =rows;
my_arr->cols=cols;
my_arr->arr= malloc(rows * cols * sizeof(*my_arr->arr));
return my_arr;
}
int main()
{
int rows = 4 , cols = 5;
myArr * my_arr = create_my_arr(4,5);
int i , j ;
for(i = 0 ; i < rows;i++)
for(j = 0 ; j < cols;j++)
{
ELEM(my_arr , i , j) = cols * i + j; // 0,1,2,3,4,5,6,7,8,...etc
}
//print array.
for(i = 0 ; i < rows;i++)
{
for(j = 0 ; j < cols;j++)
{
printf("arr[%d,%d]=%d\t" , i , j , ELEM(my_arr ,i , j));
}
printf("\n");
}
FREE_MY_ARR(my_arr);
return 0;
}
output:
gcc -o s s.c &&s
arr[0,0]=0 arr[0,1]=1 arr[0,2]=2 arr[0,3]=3 arr[0,4]=4
arr[1,0]=5 arr[1,1]=6 arr[1,2]=7 arr[1,3]=8 arr[1,4]=9
arr[2,0]=10 arr[2,1]=11 arr[2,2]=12 arr[2,3]=13 arr[2,4]=14
arr[3,0]=15 arr[3,1]=16 arr[3,2]=17 arr[3,3]=18 arr[3,4]=19

Related

How to initiliaze a dynamic 2D array inside a struct in c?

I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.

Mallocing a 3 dimensions array

I have to use a 3 dimensions array because I want to divide a pic into squares and store the average of the RGB of each square in my array.
I want it to be this size, tab[height][width][3],
so I did that:
i = 0; j = 0; k = 0;
float*** tab;
tab = malloc((hauteur+1)*sizeof(float*));
while(i <= hauteur){
tab[i] = malloc((largeur+1)*sizeof(float**) );
i++;
}
i = 0;
while(i <= hauteur){
j = 0;
while (j <= largeur){
tab[i][j] = malloc(3*sizeof(float***));
j++;
}
i++;
}
but I have a segfault after : tab[1][30][2];.
Is there a problem in my malloc?
It's strange because it doesn't segfault when I declare tab using:
tab[hauteur][largeur][3].
(Sorry: "hauteur" means "height" in French and "largeur" means "width".)
(If you think you need to check my whole function: http://pastebin.com/eqQXz8Ad; it's a writer for a JPEG file.)
Your types aren't right in your malloc calls. I'd suggest the following:
tab = malloc( (hauteur + 1) * sizeof *tab ); // sizeof (float **)
tab[i] = malloc( (largeur + 1) * sizeof *tab[i] ); // sizeof (float *)
tab[i][j] = malloc( 3 * sizeof *tab[i][j] ); // sizeof (float)
Given the declaration of tab, the following are all true:
Expression Type
---------- ----
tab float ***
*tab float **
tab[i] float **
*tab[i] float *
tab[i][j] float *
*tab[i][j] float
I usually recommend taking the sizeof of the target expression, rather than an explicit type; that way, if you ever change the type of tab (from float to double, for example), you never have to touch the malloc calls.
What you are crafting is basically an array of array of array of pointers to float, not a three dimensional array of floats.
You may want have a look at this Ambiguity in 2d array declaration in C. It works out a similar problem with a bidimensional array.
Maybe the solution for your problem can looks like:
float (*tab)[hauteur][largeur][3]; //declare a pointer to a real array
tab = malloc(hauteur * largeur * 3 * sizeof(float)); //Allocate room for threedimensional array
for (int i=0; i<hauteur; i++)
for (int j=0; j<largeur; j++)
for (int k=0; k<3; k++)
{
(*tab)[i][j][k] = (float)((i*100)+j*1000+k); //Fill elements with something using threedimensional subscripting
}
for (int i=0; i<hauteur; i++)
for (int j=0; j<largeur; j++)
for (int k=0; k<3; k++)
{
printf("[%d][%d][%d]=%f\n", i, j, k, (*tab)[i][j][k]); //Check back data...
}
EDITED
Looking at comments I see that it is someway 'unnatural' to access an array using the pointer to array notation (*array)[a][b]...[n] even if this notation explicitly report whole dimensions in declaration. To make more friendly the usage you can use the form below that allows the well known format:
#include <stdio.h>
#include <stdlib.h>
int largeur = 10;
int hauteur = 10;
int main(int argc, char *argv[])
{
float (*tab)[largeur][3]; //declare a bidimensional array of pointers to our variable
//this fools the compiler acting as a one more dimension array of variable
tab = malloc(hauteur * largeur * 3 * sizeof(float)); //Allocate room for threedimensional array
for (int i=0; i<hauteur; i++)
for (int j=0; j<largeur; j++)
for (int k=0; k<3; k++)
{
tab[i][j][k] = (float)((i*100)+j*1000+k); //Fill elements with something using threedimensional subscripting
//This use the natural addressing...
}
for (int i=0; i<hauteur; i++)
for (int j=0; j<largeur; j++)
for (int k=0; k<3; k++)
{
printf("[%d][%d][%d]=%f\n", i, j, k, tab[i][j][k]); //Check back data...
}
}
This kind of trick works because of the lack of multidimensional array concept in C language.
C knows only of array, or better it should have been string, of something, so a bidimensional array is simply an array of arrays of something. If we add one more dimension it is an array of an array of an array of something ... and so on for each more dimension we add.
This defines the memory layout of arrays in C and the addressing method that the compiler uses to access data. Because the data is streamed in memory to access a value at a specific subscript the compiler need to compute the space used for all dimensions but the very first.
+++ I fixed a bug, now the sample can be compiled under any C99-C11 compliant compiler and works.
If you care a lot about efficiency, you should consider having a single dimension array (like in Frankie_C's answer):
int height = something_to_compute_height();
int width = something_to_compute_width();
double *arr = malloc(height*width*3*sizeof(double));
if (!arr) { perror("malloc"); exit(EXIT_FAILURE); }
(as an aside, even if we both are native French speakers, let's try to use English in questions and code here)
then you might define a macro to ease speaking of some element inside arr
#define ELEM_ARR(a,i,j,k) a[i*width*height+j*width+k]
#define ARR(i,j,k) ELEM_ARR(arr)
(You've got the idea, details can be different)
This is probably more efficient than your array of pointers to array of pointers because of cache locality and because you need only one single allocation.
Choose carefully row-major or column-major access to fit the most frequent access patterns.
If height & width are specific to each array, you could use some flexible array member as last in a struct.
As a rule of thumb, it is useful in C to use multidimensional arrays only if all the dimensions (except perhaps the last) are a compile-time constant, e.g. double arr3d[3][4][5];; otherwise, better have a single-dimension array and do the index computing by yourself.
BTW, if you care a lot about performance, you might be concerned by OpenCL and OpenMP (and both usually prefer single-dimensional arrays).

function to get 2d-arrays from stack and heap

Consider a simple struct, Foo, which contains a pointer to some other strucrt, Baz. and a two-dimensional array, (stack-allocated):
Foo arr[ARR_SIZE][ARR_SIZE];
Next, consider a function which mallocs (in the heap, obviously) a memory for a new 2d-array of Foos. A code snippet:
Foo** arr_copy = malloc(sizeof(Foo*) * ARR_SIZE);
for (int i = 0; i < ARR_SIZE; i++)
{
arr_copy[i] = malloc(sizeof(Foo) * ARR_SIZE);
}
for (int i = 0; i < ARR_SIZE; i++)
{
for (int j = 0; j < ARR_SIZE; j++)
{
arr_copy[i][j].baz = malloc_baz();
}
}
Now, in my project I have various of functions which need to handle both the original array (stack allocated) and the copy (which is heap-allocated)
Problem is, things got quirky (memory looks corrupted) when I passed the copy to some function which iterate the 2d-array and print some info.
Basically, I know that there should not be a difference between: void fun(Foo** arr) to void fun(Foo arr[ARR_SIZE][ARR_SIZE]) but both ways were problematic.
So my question is, how can a function handle both arrays, stack/heap allocated?
Thanks.
If you try to do this in c or c++:
int test[][];
you will get this error:
error: declaration of 'test' as multidimensional array must have bounds for all dimensions except the first
This is because test is not in fact a double ponter as you'd expect. But the compiler converts it into a single block of data. And this:
int test[XSIZE][YSIZE];
int n = test[x][y];
will be converted into something like this:
int test[XSIZE*YSIZE];
n = test[YSIZE*x + y];
For solving this, i think #BLUEPIXY already put a solution in the comments.
Also, have a look at this question.

function to insert an element in sorted array in C

I am new to C and was writing a function to insert an element to sorted list. But my code does not display the last digit correctly. Though i know there are variety of ways to correct it but i want to know why my code isnt working, here's the code
#include <stdio.h>
int insert(int array[],int val);
int main (void)
{
int arr[5],j;
for (j = 0; j<5; j++)
{
scanf("%d",&arr[j]);
}
insert(arr,2);
for(j = 0;j<6;j++)
printf("%d",arr[j]);
return(0);
}
int insert(int array[],int val)
{
int k,i;
for (k = 0;k<5;k++)
if(val<array[k])
break;
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
}
array[k] = val;
return(1);
}
You are writing out of the range of the array here:
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
Where i+1 == 5 and you array has a range of 0 ...
4
Then you try to print the array but you go out of bounds again:
for(j = 0;j<6;j++)
printf("%d",arr[j]);
First make sure your array is large enough.
When you give a static / auto array to a function for insertion of elements, you must give: Address, Valid length, and Buffer Space unless guaranteed large enough.
When giving a dynamically allocated array, you must give pointer and valid length, you might give buffer space or guarantee enough space left to avoid reallocations.
Otherwise, you risk a buffer overrun, and UB means anything may happen, as in your example.
You're trying to make arr[6] out of arr[5] adding one val - it's impossible in C using statically allocated arrays.
To accomplish what you're trying to do you'd need to use dynamical arrays allocation:
int *arr;
int N = 5;
arr = (int *)malloc(N*sizeof(int));
then you use this arr same way as you did with arr[5] for loading data here via scanf.
And later on , while adding extra value to array - you'd need to reallocate your arr to make it bigger (read about malloc/realloc C functions):
arr = (int *)realloc((N+1)*sizeof(int));
Now your arr is of 6 int-s size.
Unfortunately if you don't know array sizes (number of elements) a priori you would need to deal with dynamical memory allocations in C.
Don't forget to release that memory in the end of the main() function:
free(arr);
You have to increase your array size from 5 to 6 as you are inserting one new element in your array, so there should be some space for that.
int arr[6];
you can also find more information in the link below:
https://learndswithvishal.blogspot.com/2020/06/insert-element-in-sorted-array.html

How to create at runtime a two dimensional array in C

I cannot create a 2D array from 2 variables (eg int arr[i][j] not allowed) so how would I create a dynamically sized 2D array?
The dimensions of the array are only known at runtime in my program. The array is to represent a grid. How would I code this in C?
First allocate an array of pointers.
/* size_x is the width of the array */
int **array = (int**)calloc(size_x, sizeof(int*));
Then allocate each column.
for(int i = 0; i < size_x; i++)
{
/* size_y is the height */
array[i] = (int*)calloc(size_y, sizeof(int));
}
You can access the elements with array[i][j]. Freeing the memory is done in 'reverse' order:
for(int i = 0; i < size_x; i++)
{
free(array[i]);
}
free(array);
You have to allocate a 1-dimensional array:
int* array = calloc(m*n, sizof(int));
And access it like this:
array[i*n + j]
The compiler does exactly this when accessing two-dimensional arrays, and will probably output the same code when n can be guessed at compile time.
This is a FAQ on comp.lang.c (I took the liberty to add the c-faq tag), it even has a FGA (frequently given answer :-)
See http://c-faq.com/aryptr/index.html, 6.16 How can I dynamically allocate a multidimensional array?
In C a multidimensional array is just an array for which each element is another array.
So you need to first allocate memory for one array (the rows). You can use the malloc() function which will return a pointer to the array.
Then you iterate through the array and for each element you allocate memory for the number of columns.
NOTE: don't forget to free the memory you manually allocate with the free() function in the same way you used malloc() to allocate it.
Some of the examples show multiple (more than 2) allocations for the array; it is perfectly feasible to do it in just two allocations (error checking omitted) for an n × m array:
int **array = calloc(m, sizeof(*array));
int *data = calloc(m * n, sizof(*data));
for (int i = 0; i < m; i++)
array[i] = &data[i * n];
...use array[i][j]...
free(array[0]);
free(array);

Resources