Passing one dimension of a 2D dynamic array to a function - c

I have a 2D array that I'm dynamically allocating at runtime, like so
accData = calloc(nbox, sizeof(double *));
for(bb = 0; bb < nbox; bb++)
accData[bb] = calloc(usedTime * usedChan, sizeof(double *));
and I want to only pass the second dimension to my function. This array represents data defined in several different "boxes", and for each box, I want to pass the relevant information to the function, process it and store it in the same array. Currently this is how I'm doing it -
for(bb = 0; bb < nbox; bb++)
fftAndsubtract(accData[bb], ntime, nchan, nsigma, bb);
where fftAndSubtract performs an FFT (fast fourier transform) and a few other operations. The function definition is like so:
int fftAndsubtract(double accData[], ntime, nchan, nsigma, bb);
but accData doesn't seem to hold the modified values that fftAndSubtract produces. I've verified this, because I'm printing the outputs of the operations done in the function itself. The compiler isn't complaining, so I didn't think this was wrong. Is there a better way to do this?
Question: Is there a way I can pass accData[bb] to the function so that the output of the operations done by the function are stored in the same array?

I'm guessing that you're on a 32-bit machine. Then pointers are 32-bits, while double are 64 bits.
This means that your allocation of the "second dimension" in the loop is wrong, and only allocates half of the data that is needed. To solve this, change to sizeof(double) in the calloc call in the loop.
Technically you might want to change the type of the accData argument in fftAndsubtract to a pointer instead, as that's what your passing it.

I like the way you're doing it, when I first read the question I was thinking you'd have to do some fancy indexing to hop from value to value... but I looked closer and I like the array of array idea. This is how I would implement it:
double *accData = calloc(nbox, sizeof(double *)); // Alloc array of double* pointers
for(bb = 0; bb < nbox; bb++)
accData[bb] = calloc(usedTime * usedChan, sizeof(double)); // Alloc array of doubles
for(bb = 0; bb < nbox; bb++)
fftAndsubtract(accData[bb], ntime, nchan, nsigma, bb);
// Remember accData is an array of an array of doubles
// accData[bb] is an array of doubles
...
int fftAndSubtract(double* accData, int nTime, int nchan, int nsigma, int bb) {
... do fancy fft stuff ...
for(int i=0; i < nTime * nchan; i++) { // loop through entire array
double result = ... do stuff with accData[i] ...
accData[i] = result;
}
return someReturnValue;
}
This is how I think about how your accData is laid out in memory (this is bad though because the first row is contiguous data and the columns (after the first row) are also contiguous data, but the columns have no correlation to each other):
double* accData[0] accData[1] accData[2] accData[3] accData[4]
double accData[0][0] accData[1][0] accData[2][0] accData[3][0] accData[4][0]
double accData[0][1] accData[1][1] accData[2][1] accData[3][1] accData[4][1]
double accData[0][2] accData[1][2] accData[2][2] accData[3][2] accData[4][2]
double accData[0][3] accData[1][3] accData[2][3] accData[3][3] accData[4][3]
double accData[0][4] accData[1][4] accData[2][4] accData[3][4] accData[4][4]

Related

Initializing C array after malloc'ing memory

I need to initialize a 2D array in C after dynamically allocating memory for it. I'm allocating memory as follows:
double **transition_mat = (double **) malloc(SPACE_SIZE * sizeof(double *));
for (int i = 0; i < SPACE_SIZE; i++) {
transition_mat[i] = (double *) malloc(SPACE_SIZE * sizeof(double));
}
but then I want to initialize it to a certain 2D array, similar to the way initialization can be done when storing the array on the stack:
double arr[2][2] = {{1.0, 7.0}, {4.1, 2.9}};
However, after allocating memory in the first code segment, trying to do assignment as follows produces an error:
transition_mat = (double **) {{1.0, 7.0}, {4.1, 2.9}};
Does anyone know of a clean way to initialize arrays after malloc'ing memory?
Note: someone suggested that I loop over 0 <= i < SPACE_SIZE and 0 <= j < SPACE_SIZE and assign values that way. The problem with that is that the entries cannot simply be computed from i and j, so that code ends up looking no cleaner than any brute force method.
If you're going to have all the data as literals in the code (to do the initialization), why not just store that as an explicit 2D array to begin with, and be done?
Worst case, do the dynamic allocation and copy from your existing array.
Make it static const inside the function, or at global scope, depending on the access pattern you need.

Crash while re-organizing 1d buffer as 2d array

I have a 1d buffer which i have to re-organize to be accessed as a 2d array. I have pasted my code below:
#include <stdlib.h>
#include <stdio.h>
void alloc(int ** buf, int r, int c)
{
int **temp=buf;
for(int i=0; i<r; i++)
buf[i]=(int *)temp+i*c;
}
void main()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = (int**) buffer;
alloc(p, 4, 4);
//for(int i=0;i<r;i++)
//for(int j=0;j<c;j++)
// printf("\n %p",&p[i][j]);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
}
The code is crashing when i make the assignment.
I have ran the code for different test cases. I have observed that the code crashes when there is an assignment to p[0][x] followed by assignment to p[x][anything] with the code crashing at the second assignment. This crash is seen only when the first index of the first assignment is 0 and for no other indices with the crash happening at the second assignment having the first index equal to the second index of the first assignment.
For example, in the above code crash happens at p[3][2] after p[0][3] has been executed. If i change the first assignment to p[0][2] then crash would happen at p[2][3]( or p[2][anything] for that matter).
I have checked the memory pointed to by p, by uncommenting the double for loop, and it seems to be fine. I was suspecting writing at illegal memory locations but that has been ruled out by the above observation.
The problem is that your 2D array is actually an array of pointers to arrays. That means you need to have space for the pointers. At the moment you have your pointers in positions 0-3 in the array, but p[0] is also pointing to position 0. When you write to 'p[0,3]' you are overwriting p[3].
One (tempting) way to fix it is to allow the pointers room at the start of the array. So you could change your alloc method to allow for some space at the front. Something like:
buf[i] = (int *)(temp+r) + i*c;
Note the +r adding to the temp. It needs to be added to temp before it is cast as you can't assume int and int * are the same type.
I would not recommend this method as you still have to remember to allocate extra space in your original malloc to account for the array of pointers. It also means you aren't just converting a 1D array to a 2D array.
Another option would be to allocate your array as an array of pointers to individually allocated arrays. This is the normal way to allocate 2D arrays. However this will not result in a contiguous array of data as you have in your 1D array.
Half way between these two options, you could allocate an extra array of pointers to hold the pointers you need, and then point them to the data. Change your alloc to something like:
int **alloc(int * buf, int r, int c)
{
int **temp = (int **)malloc(sizeof (int *)* r);
for (int i = 0; i<r; i++)
temp[i] = buf + i*c;
return temp;
}
then you call it like:
int **p = alloc(buffer, 4, 4);
you also need to free up the extra buffer.
This way your data and the pointers you need to access it are kept separate and you can keep your original 1D data contiguous.
Note that you don't need to cast the result of malloc in c, in fact some say that you shouldn't.
Also note that this method removes all of the requirement for casting pointers, anything that removes the need for a cast is a good thing.
I think that your fundamental problem is a misconception about 2D arrays in C (Your code is C, not C++).
A 2D array is a consecutive memory space , and the size of the inner array must be known in advance. So you basically cannot convert a 1D array into a 2D array unless the size of the inner array is known at compile time. If it is known, you can do something like
int *buffer=(int *)malloc(sizeof(int)*100);
typedef int FourInts[4];
FourInts *p = (FourInts *)buffer;
And you don't need an alloc function, the data is already aligned correctly.
If you don't know the size of the inner array in advance, you can define and allocate an array of arrays, pointing into the 1D buffer. Code for that:
int ** alloc(int * buf, int r, int c)
{
int **array2d = (int **) malloc(r*sizeof(int *));
for(int i=0; i<r; i++)
array2d[i] = buf+i*c;
return array2d;
}
void _tmain()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = alloc(buffer,4,4);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
free(buffer);
free(p);
}
But it would have been easier to simply build an array of arrays without using the buffer. If you could use C++ instead of C, then everything could be easier.
If you already have a 1D block of data, the way to make it accessible as a 2D array is to create an array of pointers - one for each row. You point the first one to the start of the block, the next one is offset by the number of columns, etc.
int **b;
b = malloc(numrows*sizeof(int*));
b[0]=temp; // assuming temp is 1D block
for(int ii=1; ii<numrows;ii++)
b[ii]=b[0]+ii*numcols;
Now you can access b[i][j] and it will point to your original data. As long as number of rows and columns are known at run time this allows you to pass variable length 2D arrays around. Remember that you have to free the vector of pointers as well as the main data block when you are done or you will get a memory leak.
You will find examples of this if you google nrutil.c - this is derived from the trick Numerical Recipes in C uses.
This function prototype should be:
void alloc(int *buf[][], int r, int c) //buf[][] <=> **buf, but clearer in this case
{
//*(buf[i]) =
...
}
If you want to work on the same array you have to pass a pointer to this 2D array (*[][]).
The way you do it now is just working on a copy, so when you return it's not modified.
You should also initialize your array correctly :
p = malloc(sizeof(int *[]) * nb of row);
for each row
p[row] = malloc(sizeof(int []) * nb of col);

Correct way to allocate and free arrays of pointers to arrays

I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?
float *array1[SIZE]; // I think it is automatically allocated
// OR
float **array1 = calloc(SIZE, sizeof(float*));
free(array1);
for (int i = 0; i < SIZE; i++) {
array1[i] = (float[]){0,0,0};
// OR
array1[i] = calloc(3, sizeof(float));
}
Then how would I free the data? I'm pretty sure just free(array1); wouldn't work, so would I free each pointer in the array then free the array, or since I allocated three floats, would I free each float, then each 3 float array, then the whole array???
If you know the array size at compile time (and you do, if SIZE is a compile-time constant), you should just declare a two-dimensional array. You don't need to free this at all (and must not).
float array1[SIZE][3];
You need to use calloc, and to create an array of pointers, only if the dimensions are not known at compile time. In this case, there should be one call to free for each call to calloc. And since you cannot use an array after you free it, you need to free the row arrays before you free array1.
float **array1 = calloc(nrows, sizeof (float *));
for (int i=0; i < nrows; i++)
array1[i] = calloc(3, sizeof(float));
// Use it...
// Now free it
for (int i=0; i < nrows; i++)
free(array1[i]);
free(array1);
Edit: if you won't be rearranging the pointers (to sort the rows in-place, for example), you can do all of this with just one calloc (and one call to free afterwards):
float (*array1)[3] = calloc(3*nrows, sizeof (float));
That's because the number of columns is known at compile-time, and that's all the pointer arithmetic needs to know. Then you can write things like array1[i][j], and you can still pass around array1[i] as if it was a real pointer to a row. C is great that way, take advantage of it!
A general rule is that for each time you call malloc() or calloc() you will need to do a free() call on the returned pointer.
If you want a two dimensional array with compile-time known size, just use a two dimensional array! float val[5][3] is perfectly valid.
If you want a two dimensional array and you don't know it's size during compile-time, you most probably want to use a standard, single diemensional calloc() and an appropriate getter.
#define ARR_COLUMNS 10
#define ARR_ROWS 10
float* arr = calloc (ARR_COLUMNS * ARR_ROWS, sizeof(float));
int get(float* arr, int x, int y) {
if (x<0 || x>= ARR_COLUMNS) return 0;
if (y<0 || y>= ARR_ROWS) return 0;
return arr[ARR_COLUMNS*y+x];
}
void set (int* arr, int x, int y, float val) {
if (x<0 || x>= ARR_COLUMNS) return;
if (y<0 || y>= ARR_ROWS) return;
arr[ARR_COLUMNS*y+x] = val;
}
Of course replace the defines with appropriate variables.
By doing so you will:
save yourself costly allocs and frees
have less fragmented memory
simplify your possible realloc calls
ensure the data is cached better and accessed without the common [x][y] vs [y][x] iteration cache problem.
I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?
Why do you want an array of pointers to arrays? Wouldn't an array of arrays be sufficient? (Keep in mind that arrays are already pointer-like, they are not passed by value, rather the address of the first element is passed when an array is passed as an argument to a function).
// stack allocation, no need to free
float array[SIZE][3];
for (int i = 0; i < SIZE; i++) {
// do something with array[i][0], array[i][1], array[i][2]
}
Then how would I free the data?
In this case you wouldn't, since the data is stack allocated (will be cleaned up automatically once out of scope). Just remember the rule of thumb is that for every memory allocation you make, a corresponding free is necessary. So if you allocate memory for an array of floats, as in
float* arr = malloc(sizeof(float) * 3); // array of 3 floats
Then you only need to call free on the array that you malloc'd, no need to free the individual floats. If you perform nested allocation as in
// array of length SIZE, consisting of float pointers
float** arr = malloc(sizeof(float*) * SIZE);
// allocate the array of 3 floats at each index
for (int i = 0; i < SIZE; i++)
arr[i] = malloc(sizeof(float) * 3);
Then you will need to perform a free for every malloc, as in
// free the individual arrays
for (int i = 0; i < SIZE; i++)
free(arr[i]);
// free the array of arrays
free(arr);
The lesson to take away here is to avoid dynamic allocation of arrays all-together. Stick with either std::vector or stack-allocated arrays.

C: I need a function which will accept and return a variably sized array

If this is a beginner's question, my apologies - most of my programming has been in very high level langauges, and I have limited expertise in C. (This is the sort of thing I could do very easily in languages such as Matlab, Octave, Sage, Maxima etc, but for this I need the speed of C).
But anyway... I have an array whose size is set at run time with malloc:
int *A = malloc(m * sizeof(int));
where m is computed from some values provided by the user. I have a function "update" which updates the array (or, if you prefer, takes the array as input and returns another as output). This update function may be called upwards of 10^8 times.
So the function itself can't introduce the appropriately sized output array with malloc, or the memory will be used up. So, for example, I can't do this:
int * update(int *L) /* produces next iteration of L */
{
int *out = malloc(m * sizeof(int));
/* do some stuff with L and produce new array out */
return (out);
}
I've tried to make out a static variable outside the update function:
static int *out;
and define its size in main:
out = malloc(m * sizeof(int));
But this doesn't seem to work either.
Anyway, I would be very grateful of some advice - I think I've exhausted the excellence of google.
Allocate the array outside of update, then pass a pointer to it:
void update(int const *L, int *out)
{
// whatever
}
Call as
int *A = malloc(m * sizeof(int));
if (A == NULL)
// handle error
for (i=0; i < N_ITER; i++)
update(L, A);
Though you may want to redesign the program so that it updates L in-place.
So if you are simply wanting to work on the data that is coming into the function directly, then what you have is partially already correct. The only thing that I would do is to add the size of the array as an input parameter to the routine to look like this:
void update(int * L, unsigned int size){
unsigned int count;
// Make sure the array has actually been allocated from outside
if(L == NULL) return;
// Example work on L just as if it is an array of values
for(count = 0; count < size; count++){
L[count] = L[count] + 1;
}
}
REMEMBER, this will work if you DO NOT wish to maintain the original data within L. If you do wish to maintain the original data, then larsmans answer will work better for you.
Also remember that you will have to malloc whatever variable you wish to input into L, outside and prior to your update routine, and free at some other point.
int * myVar = (int *)malloc(m * sizeof(int));
update(myVar, m);
// Other work to be done
free(myVar);
You should use realloc.
int *a = realloc(a, m * sizeof(a[0]));
It will work just as malloc in the first run but then it will reallocate a different sized array. You should note that the new array might or might not have the previous values assigned in it. You should assume that it has garbage like all things given by malloc.
Here is a good explanation of using realloc.
http://www.java-samples.com/showtutorial.php?tutorialid=589
NOTE : sizeof(a[0]) is equal to sizeof int but if you change int it will still be right

Why does my 2D array cause a bus error in C?

I'm attempting to create a simple 2D array in C but apparently running into some memory trouble. My setup is simple enough and I can't tell what's wrong. I admit that my understanding of pointers is insufficient, but I still think this should be working. Can anyone see the flaw here?
typedef unsigned int DATUM;
DATUM **series_of_data;
void initialize_data()
{
*series_of_data = (DATUM *) malloc(1024 * sizeof(DATUM));
}
This causes my program to crash with a bus error when I run it.
series_of_data is actually not allocated.
You have various way to allocates a 2D array, either using the array of rows model whcih has bad cache coherency and thus has usually bad performances or to use the Iliffe vector adviced in Numerical recipes in C that consists in allocating one huge h*w memory block and a side pointer array which contains the beginning of your rows (or columns) :
DATUM** alloc_array( int h, int w )
{
int i;
DATUM** m = (DATUM**)malloc(h*sizeof(DATUM*));
m[0] = (DATUM*)malloc(h*w*sizeof(DATUM));
for(i=1;i<h;i++) m[i] = m[i-1]+w;
return m;
}
void release_array(DATUM** m)
{
free( m[0] );
free( m);
}
int main()
{
int r,c;
DATUM** tab;
int width = 5;
int height = 3;
tab = alloc_array(height, width); /* column first */
for(r = 0;r<height;++r)
for(c = 0;c<width;++c)
tab[r][c] = (1+r+c);
for(r = 0;r<height;++r)
{
for(c = 0;c<width;++c)
{
printf("%d\t",tab[r][c]);
}
puts("");
}
release_array(tab);
}
Data are nicely packed in memory, so cache are happy and you keep the [][] access pattern.
As a matter of speed this is in +/-3% speed of the classical DATUM* + polynomial access method.
series_of_data is an invalid pointer - you don't assign it to anything. When you try to assign to its memory location (*series_of_data = ...), it's putting stuff in a random place, which is likely to not do what you want. You have to point series_of_data somewhere useful, e.g.
series_of_data = (DATUM **)malloc(16 * sizeof(DATUM *))
for an array with 16 slots for DATUM * pointers in it.
You haven't allocated the series_of_data pointer before you assign to *series_of_data.
For example, if series_of_data is intended to be an array then you would need to write something like this:
series_of_data = malloc(n*sizeof(DATUM*));
where n is the length of the series_of_data array.
Only after you have done this can you assign to *series_of_data.

Resources