Mallocing a 3 dimensions array - c

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).

Related

Shift elements by one index with memmove

I am trying to shift the elements in a dynamically created 3d array by one index, so that each element [i][j][k] should be on [i+1][j][k].
This is how my array creation looks like
typedef struct stencil{
int ***arr;
int l;
int m;
int n;}matrix;
void createMatrix(matrix *vector){
vector->arr = (int***) malloc(sizeof(int**) * (vector->l+2));
for (int i = 0; i< vector->l+2; ++i) {
vector->arr[i] = (int**) malloc(sizeof(int*) * (vector->m+2));
for (int j = 0; j < vector->m+2; ++j) {
vector->arr[i][j] = (int*) calloc((vector->n+2),sizeof(int));
}
}
}
This is basically what I want to achieve with memmove
for(int i = vector->l-1; i >= 0; --i){
for(int j = vector->m; j >= 0; --j){
for(int k = vector->n; k >= 0; --k){
vector->arr[i+1][j][k] = vector->arr[i][j][k];
}
}
}
for some reason memmove shifts 2 indices.
memmove(&(vector->arr[1][1][1]), &(vector->arr[0][1][1]), (vector->l+2)*(vector->m+2)*(vector->n)*sizeof(int*));
Could anyone give me a hint?
When you create a dynamic multi-dimensional array like this, the array contents are not contiguous -- each row is a separate allocation. So you can't move it all with a single memmov().
But you don't need to copy all the data, just shift the pointers in the top-level array.
int **temp = arr[l-1]; // save last pointer, which will be overwritten
memmov(&arr[1], &arr[0], sizeof(*arr[1]));
arr[0] = temp;
I've shifted the last element around to the first, to avoid having two elements that point to the same data. You could also free the old last element (including freeing the arrays it points to) and create a new first element, but this was simpler.
Compile with a higher optimization level (-O3). Obtain a direct reference on vector->arr instead of forcing dereferencing on every single array access.
Your call to memmove looks half correct under the assumption that you allocated arr as continuous memory. However, since you said "dynamic", I very much doubt that. Plus the size calculation appears very much wrong, with the sizeof(int*).
I suppose arr is not int arr[constexpr][constexpr][constexpr] (single, continuous allocation), but rather int ***arr.
In which case the memmove goes horribly wrong. After moving the int** contents of the arr field by one (which actually already did the move), it caused a nasty overflow on the heap, most likely by chance hitting also a majority of the int* allocations following.
Looks like a double move, and leaves behind a completely destroyed heap.
Simply doing this would work (Illustrating in a 3d array)
memmove(arr[1], arr[0], Y*Z*sizeof(int));
where Y and Z denotes the other 2 dimensions of the 2d array.
Here arr[X][Y][Z] is the int array where X>=2.
In case of dynamically allocated memory you need to do each continuous chunk one by one. Then it would work.

How to dynamically allocate 2D array of POINTERS in ANSI C?

I meet a case that I want to have an array of pointers(M rows, N cols), each member of this array points to a float vector (Lā€‘length). Could you tell me how to establish it? I hope I can establish it dynamically because I usually don't know M, N, and L at first and L may be different for difference vector.
My occasion is that I need to read Green function with different distance(NDIS) and depth(NDP). So I need to create something like *grn[NDP][NDIS]. then use each pointer of this array to point to a component of green function.
By the way, I think it's a little bit complex than setting a size known array of pointers. Do you think it's worth to use this type of data structure? I'm trying to write a program to deal with observation, which I usually unknown it's size.
However, it's ok for me to use a size-fixed array of pointers. If the total data is larger than the given size, I could ignore the over-sized part. But I'd hope to use them all.
You need to use the 2-d array and need to allocate it Dynamically, like this:
int i, j;
float **arr;
arr = malloc(sizeof(float*) * Size1); //1st array setup
for(i = 0; i < Size1; i++)
arr[i] = malloc(sizeof(float*) * Size2); // 2nd array setup at each element of 1st array
Now accessing it like this:
for(i = 0; i < Size1; i++)
for(j = 0; j < Size2; j++)
printf("%f", arr[i][j]);
Size1 & Size2 are sizes of first array and second array.
You can setup different sizes of individual arrays in first array elements, for that you need to do it without loop and by changing the Size2 variable.
Hope this helps.

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.

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

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

C arrays and pointers

Just started to learn C language.
I have a pointer array int *parr and I need to fill it with random numbers and then do some other things with it.
But I even don't understand how to fill it with random numbers. I tried something like this, but it hangs the program:
for(i=0 ; i<R ; i++)
{
for(j=0 ; j<C; j++)
{
*(parr+i*C+j)=rand() % 10;
printf("%d",*(parr+i*C+j));
}
printf("\n");
}
The way you initialize it, you probably have to malloc memory like this:
parr = malloc(R * C * sizeof(*parr));
int *parr;
just defines a pointer to a n integer, but there's no storage associated with it. You could either
int parr[sizeofarray];
or
int *parr = calloc (sizeofarray, sizeof(int));
to obtain the right amount of storage.
based on your example sizeofarray should be at least R * C.

Resources