multi-dimension array allocation with calloc - c

I have the following 2-dimension array N*2 (I can't modify its declaration):
bool* myArray[2];
int N;
I want to allocate it with calloc but no success:
myArray = calloc(N, 2*sizeof(bool));
for (int i=0; i!=N; i++)
{
myArray[i] = calloc(2, sizeof(bool));
}
The compiler raises me (on the first calloc):
error: incompatible types in assignment of 'void*' to 'bool* [2]'
what am I doing wrong?

This code:
bool* myArray[2];
int N;
doesn't declare a 2-dimensional array but an array of pointers. This is an important difference because 2-dimensional arrays are not arrays of pointers to arrays -- they are just stored contiguously, like 1-dimensional arrays are (one "row" after the other).
So, as you state you cannot change the declaration, let's instead explain what you need for an array of pointers. With your declaration, you declare exactly 2 pointers, so N can only mean the "second dimension" as in the number of elements in the arrays those pointers point to. With this declaration, you can have 2 times an array of N bools. Allocating them would look like this:
myArray[0] = calloc(N, sizeof(bool));
myArray[1] = calloc(N, sizeof(bool));
There's no need to allocate space for myArray itself, with your declaration, it already has automatic storage.

Do this instead:
bool (*myArray)[2] = calloc(N, sizeof(*myArray));
Or, if you do not wish to modify your declaration, just get rid of the first calloc here and modify your for loop:
myArray = calloc(N, 2*sizeof(bool)); // you do not need that
for (int i=0; i < 2; i++)
{
myArray[i] = calloc(N, sizeof(bool));
}
PS: In C we don't cast malloc, we do that when we wish to compile C++.

The reason you can't reallocate myArray is that myArray is not a pointer. It is an array of two pointers to bool. It is also, contrary to your description, not a "2-dimension array".
All you need to do is
for (int i=0; i < 2; ++i)
{
myArray[i] = calloc(N, sizeof(bool));
}
and you can then use as a '2*N' array, for example to set all elements to true;
for (int i = 0; i < 2; ++i)
{
for (j = 0; j < N; ++j)
myArray[i][j] = true;
}
If you swap the order of indices (e.g. use myArray[j][i] in the inner loop above) and use myArray as a 'N*2' array rather than as a '2*N' array, the result will be undefined behaviour. There is no solution to change that, without changing the declaration of myArray - which you have said you do not want to do.

Related

Using pointer of pointer to reference a matrix [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 3 years ago.
I am very new to C, and I am trying to get a int **data to represent a matrix of integers.
I first created an array of arrays, then I tried referencing the pointer of pointer to that array like so:
int **pointer;
int data[num_rows][num_cols];
pointer = (int**) data[0];
However I get a warning: cast to pointer from integer of a different size.
Can someone please help me understand what is going on, and how can I assign an array to int **pointer? (I have to use the double pointer)
The line int data[num_rows][num_cols]; does not actually declare an "array of arrays!" Rather, it declares a single array with two dimensions - in memory, this will be a single block of data, of size num_rows x num_cols x sizeof(int).
To get an "array of arrays" that you can access using a 'double pointer', you generally have to use the malloc function. Something like the following:
int **pointer = malloc(num_rows * sizeof(int*)); // allocate an array of pointers
for (int i = 0; i < num_rows; ++i) {
pointer[i] = malloc(num_cols * sizeof(int)); // allocate each row array
}
You can then access any [row][column] element via the double pointer:
pointer[row][column] = 1234;
When you've finished with the array(s), be sure to free the memory, like this:
for (int i = 0; i < num_cols; ++i) {
free(pointer[i]); // free each row array
}
free(pointer); // free the array of arrays
Alternatively, given your int data[num_rows][num_cols]; you could avoid the malloc calls inside the for loop, as follows:
int **pointer = malloc(num_rows * sizeof(int*)); // allocate an array of pointers
for (int i = 0; i < num_rows; ++i) {
pointer[i] = &data[i][0]; // Assign a pointer to the beginning of each row
}
Feel free to ask for further clarification and/or explanation.

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.

Accessing elements in a two dimensional lattice C

Why can I not access Lattice using [ ][ ] without raising a seg fault?
int *LatticeHeight;
int **Lattice;
LatticeHeight = (int*)malloc(Height*sizeof(int));
Lattice = (int**)malloc(Length*sizeof(LatticeHeight));
for(i=0;i<Height; i++)
{
for(j=0; j<Length; j++)
{
Lattice[j][i] = 0;
}
}
I'm interpreting this as;
I have my pointer to one dimensional array of height
Then I set Lattice so that is can store Length-many copies of LatticeHeight (making a grid)
Then I access each element of the lattice and set it's value to 0
Moreover could someone explain why this works in 1D but not in 2D, i.e.
for(i=0;i<Height;i++)
{
LatticeHeight[i] = 0;
}
Does not throw a seg fault
You didn't allocate the array properly. Your first malloc allocates one row; your second malloc allocates space to store a pointer to each row but it does not actually allocate any rows to go in there (and it does not have any association to the single row you allocated earlier, either).
The simplest way to write this code, if you do not require to have rows of different lengths to each other, is to allocate a single memory block:
int (*Lattice)[Length] = calloc( Height, sizeof *Lattice );
If you do want to have a jagged array for some reason (i.e. each row is allocated in a separate memory block) then the code is:
int **Lattice = malloc( Height * sizeof *Lattice );
for ( size_t row = 0; row != Height; ++row )
Lattice[row] = calloc( Length * sizeof **Lattice );
Note that calloc allocates the memory and also zeroes it, so you don't need your zero loop afterwards, and don't cast malloc
I think you should initialize your array like this:
Lattice = (int**)malloc(Length*sizeof(int*));
for(int i = 0; i < Length; ++i) {
LatticeHeight = (int*)malloc(Height*sizeof(int));
}
You have to allocate memory for Lattice which is a pointer to a pointer to int.
Lattice = malloc(Length * sizeof(LatticeHeight));
And then iterate through the "array" of pointers to int that you just have created and allocate memory for each one, like this.
for(i = 0; i < Lenght; i++)
LatticeHeight = malloc(Height * sizeof(int));
With that you would have a two-dimensional "array".
Although, as Matt McNabb said, there are other options for what you want to do.

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