Allocating 2D array with pointer to fixed-size array - c

Is it valid in C to dynamically allocate 2d arrays this way?
//fixed size
int (*arr2d)[9][9]=malloc(sizeof(int[9][9]));
//variable size
int x=5,y=3;
int (*arr2d)[x][y]=malloc(sizeof(int[x][y]));
//assignment
(*arr2d)[0][1]=2;
EDIT:
By "valid" I mean, are there any pitfalls as opposed to:
int i,x=5,y=10;
int **arr2d=malloc(sizeof(int*[x]));
for(i=0;i < x;i++)
arr2d[i]=malloc(sizeof(int[y]));
arr2d[0][0]=5;

The only real issue is if you request more memory than the malloc call can satisfy (you may have enough memory available, but not in a single, contiguous block).
To save your sanity, do something like this instead:
T (*arr)[cols] = malloc( sizeof *arr * rows );
This will allow you to index it as arr[i][j] instead of (*arr)[i][j].

Related

Letting the user define size of an array

How can I let the user choose a number say n and then create an array with the size of n?
Can I just say int a[]=malloc (n*sizeof(int))?
There are two ways to do that. If the array size is small then you can use variable length array
/* Valid in C99 and later */
int n;
scanf("%d", &n);
int a[n];
This will allocate memory on stack. Other way is you can use dynamic memory allocation which will allocate memory on the heap
int *a = malloc(n*sizeof(int));
Your idea is nearly correct:
int a[] = malloc(n*sizeof(int));
Using malloc is the correct way.
But you cannot assign the returned address to an array.
You must use a pointer variable instead:
int *a = malloc(n*sizeof(int));
Yes if u want to set the size of the array at run-time.
Then u should go for dynamic memory allocation(malloc/calloc).
int a[]=malloc (n*sizeof(int));//this not possible.
int *a =malloc (n*sizeof(int)); // this is possible.
There are two basic ways for allocating the memory to create an array where the size to the array is determined as input:
The first one is,
allocating the memory for array in the 'stack' segment of memory where the size of array is taken as input ant then the array of that particular size is defined and granted memory accordingly.
int n;
scanf("%d",&n); //scanning the size
int arr[n]; //declaring the array of that particular size here
The second one is,
allocating the required memory in the 'heap' segment of memory.It is the memory allocated during runtime (execution of the program)
So,another way of declaring an array where size is defined by user is
int n,*arr;
scanf("%d",&n);
arr=malloc(n*sizeof(int)); //malloc function provides a contiguous space
or
arr=calloc(n,sizeof(int)); //calloc function is similar,initializes as 0
to use both these functions make sure to include stdlib.h.
Variable length arrays (VLAs) were added to C with C99, but made optional with C11. They are still widely supported, though. This is the simplest way to define an array with user-selected size at runtime.
Other than that VLAs may not be available on all platforms, they also may fail silently when there is an allocation failure. This is a disadvantage that malloc() avoids when used correctly.
You can't assign to an array in C, and instead you need to store the value returned by malloc() in a pointer. Note that malloc() returns NULL when there is an allocation failure, allowing code to check for failure and proceed accordingly. The actual allocation might look like this:
int *a_dyn = malloc(sizeof *a_dyn * arr_sz);
This is an idiomatic way of calling malloc(). Note that there is no need to cast the result of malloc(), and note that the operand to sizeof is not an explicit type, but rather an expression involving a_dyn. The sizeof operator uses the type of the expression *a_dyn, which is in fact int (there is no dereference made). This is less error-prone and easier to maintain when types change during the life of a program than coding with explicit types. Also note that the sizeof expression comes before arr_sz. This is a good practice to follow: sometimes you might have a call like:
int *arr = malloc(sizeof *arr * nrows * ncols);
Placing sizeof first forces the multiplication to be done using size_t values, helping to avoid overflow issues in the multiplication.
Don't forget to free any memory allocated with malloc() when it is no longer needed, avoiding memory leaks.
Whether you use a VLA or malloc(), you must validate user input before using it to avoid undefined behavior. Attempting to allocate an array of non-positive size leads to undefined behavior, and attempting to allocate too much memory will lead to an allocation failure.
Here is an example program that illustrates all of this:
#include <stdio.h>
#include <stdlib.h>
#define ARR_MAX 1024 // some sensible maximum array size
int main(void)
{
int arr_sz;
int ret_val;
/* validate user input */
do {
printf("Enter array size: ");
ret_val = scanf("%d", &arr_sz);
} while (ret_val != 1 || arr_sz < 1 || arr_sz > ARR_MAX);
/* use a VLA */
int a_vla[arr_sz];
for (int i = 0; i < arr_sz; i++) {
a_vla[i] = i;
printf("%d ", a_vla[i]);
}
putchar('\n');
/* use malloc() */
int *a_dyn = malloc(sizeof *a_dyn * arr_sz);
if (a_dyn == NULL) { // malloc failure?
fprintf(stderr, "Unable to allocate memory\n");
} else { // malloc success
for (int i = 0; i < arr_sz; i++) {
a_dyn[i] = i;
printf("%d ", a_dyn[i]);
}
putchar('\n');
}
/* avoid memory leaks */
free(a_dyn);
return 0;
}

How can i use dynamic 2d array in c

I tried to make a dynamic 5x5 int array
int **data=malloc(5*5);
But I get segmentation fault on trying to access it.
You need to allocate memory for the 2d-array you want to make (which I think you understand). But first, you will have to allocate the space for pointers where you will store the rows of the 2D-array.
int **data=(int**)malloc(sizeof(*data)*5); //Here 5 is the number of rows
Now you can allocate space for each row.
for(int r=0;r<5;r++){
data[r]=(int*)malloc(sizeof(**data)*5);//here 5 is the width of the array
}
If you want contiguous block of memory for the whole array, you can allocate a single dimension array of size 25, and access it like data[r*5+c].
PS: Instead of sizeof(*data) and sizeof(**data), you can use sizeof(int*) and sizeof(int) to avoid confusion with *
PS: If you are not using C++, removing the casts from return value of malloc is better (see comments).
If you want a single contiguous memory block to hold 5x5=25 integers :
int *data = malloc(5*5*sizeof(*data));
If you want a 2d array with size 5x5
int **data = malloc(5*sizeof(*data));
for (int i=0; i<5; ++i)
data[i] = malloc(5*sizeof(**data));
There are two possibilities. The first one is indeed to allocate a two-dimensional array:
int ( *data )[5] = malloc( 5 * 5 * sizeof( int ) );
In this case one contiguous extent is allocated for the array.
The second one is to allocate at first a one-dimensional array of pointers and then allocate one-dimensional arrays pointed to by the already allocated pointers.
For example
int **data = malloc( 5 * sizeof( int * ) );
for ( size_t i = 0; i < 5; i++ )
{
data[i] = malloc( 5 * sizeof( int ) );
}
In this case there are allocated in fact 6 extents of memory: one for the array of the pointers and other 5 for arrays of integers.
To free the allocated memory in the first example it is enough to write
free( data );
and in the second example you need to write the following
for ( size_t i = 0; i < 5; i++ ) free( data[i] );
free( data );
If you want to treat the array as a 2D array (a[i][j]) and you want all the array elements to be contiguous in memory, do the following:
int (*data)[5] = malloc( sizeof *data * 5 );
If you also want to be table to determine the size of the array at run time and your compiler supports variable-length arrays1:
size_t rows, cols;
...
int (*data)[rows] = malloc( sizeof *data * cols );2
If your compiler does not support VLAs and you still want to determine the array size at runtime, you would do:
size_t rows, cols;
...
int **data = malloc( sizeof *data * rows );
if ( data )
{
for ( size_t i = 0; i < rows; i++ )
{
data[i] = malloc( sizeof *data[i] * cols );
}
}
The downside of this approach is that the rows of the array are not guaranteed to be contiguous in memory (they most likely won't be). Elements within a single row will be contiguous, but rows will not be contiguous with each other.
If you want to determine the array size at runtime and have all the array elements be contiguous in memory but your compiler does not support variable-length arrays, you would need to allocate a 1D array and manually compute your indices (a[i * rows + j]):
int *data = malloc( sizeof *data * rows * cols );
1. VLAs were introduced with C99, but then made optional in C2011. A post-C99 compiler that does not define the macro __STDC_NO_VLA__ should support VLAs.
2. Caution - there is some question whether sizeof *data is well-defined in this example; the sizeof expression is normally evaluated at compile time, but when the operand is a VLA the expression is evaluated at run time. data doesn't point to anything yet, and attempting to dereference an invalid pointer leads to undefined behavior. All I can say is that I've used this idiom a lot and never had an issue, but that may be due more to bad luck than design.
Here is the answer:
int ** squaredMatrix;
int szMatrix=10;
squaredMatrix= (int**)malloc(szMatrix*sizeof(int*));
for making 2d arrays you should view them as one array which every block is an array again .
for example in above picture , blue blocks make an array which each blue block is pointing to an array ( every 4 green blocks in a row are an array and blue blocks in a column are the main array)

Declaring an 2 dimensional array with size according to input

Say, I want an array of words that is of max length 20. I get the number of words to be stored from user input. What is the most memory efficient way to declare the above array?
I could do something like this, but I guess its not very memory efficient?
char wordArray[1000][20];
That is I want "1000" to varies accordingly to user's input. And I can't do this.
int main()
{
int size;
printf("Enter size: ");
scanf("%d", &size);
char wordArray[size][20];
}
Generally stack size is small and you can't allocate such a big amount of memory on stack. Doing so will result in stack overflow. You need dynamic allocation.
int size;
printf("Enter size: ");
scanf("%d", &size);
char **wordArray = malloc(size*sizeof(char *));
for(int i = 0; i < size; i++)
wordArray[i] = malloc(20);
Call free to deallocate.
But, note that this will allocate defragmented memory instead of continuous unlike as in case of 2D array. To get continuous memory allocation you can use pointer to array as
int (*wordArray)[20] = malloc(size * sizeof(*wordArray));
and access the element as wordArray[i][j].
For more detailed explanation read c-faq 16.6: How can I dynamically allocate a multidimensional array?
Nope, it is not, because you're imposing an allocation of 100000 times sizeof(char) of memory. And no, you can't do as you wrote here, because during the compile-time the size of array is unknown, so space cannot be allocated. You could do it using malloc.

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.

Resources