Creating a dynamic array of arrays using pointers - c

I'm trying to create a dynamic array of arrays. So, for example, let's look at Pascal's Triangle:
1
11
121
1331
14641
...
...
This is basically an array of length N, that has at each index an array of i+1.
How exactly do we set that up?
I've tried a little bit using pointers.
I set up an array of pointers like such:
int *arr[N];
Then I need a pointer i to point to an array of i+1, so I did:
int *i = 0;
for(int j = 0; j < N; j++){
int numArr[j+1];
arr[*i] = numArr;
*i++;
}
Am I going the right direction for this? Because I believe I'm supposed to allocate memory for this as I must use free() later. Would I use malloc() for each array initialization?

The code could be made extremely simple, if you know what you're doing:
int *arr = malloc(N * sizeof(int*));
int i;
for (i = 0; i < N; ++i) {
arr[i] = malloc(sizeof(int) * (i + 1));
}
Of course, you'll need corresponding calls to free() further down the line, like this:
for (i = 0; i < N; ++i) {
free(arr[i]);
}
free(arr);

Related

Simple 2D array with calloc resulting in Segmentation fault

I'm getting a strange "Segmentation fault: 11" with this simple code and can't figure it out what is the problem. I just need to dynamically declare and array with size nrows x ncolumns.
#include <stdlib.h>
#include <stdio.h>
int main()
{
int nrows = 3;
int ncolumns = 5;
int **array;
array = calloc(nrows, sizeof(int));
for(int i = 0; i < nrows; i++)
{
array[i] = calloc(ncolumns, sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit(-1);
}
}
for(int i = 0; i < nrows; i++)
{
for(int j = 0; j < ncolumns; j++)
{
array[i][j] = 10;
printf("%d %d: %d\n",i,j, array[i][j]);
}
}
return 0;
}
You're mixing your metaphors. You declare your array to be a block of pointers to pointers, but then allocate int sized memory blocks. You might just get away with this where the size of a pointer is the size of an int, but it's still incorrect.
The simplest option is to make it a simple 1D array that you access with row and column strides (ie, array[row*ncolumns + column]), or to use pointers more thoroughly throughout.
Note that you can't use doubled up array syntax to access this sort of dynamically allocated 2D array, as the compiler does not know the size of the inner array, and because of that, the stride of the outer array.

Allocating contiguous memory for a 3D array in C

I need to allocate contiguous space for a 3D array. (EDIT:) I GUESS I SHOULD HAVE MADE THIS CLEAR IN THE FIRST PLACE but in the actual production code, I will not know the dimensions of the array until run time. I provided them as constants in my toy code below just to keep things simple. I know the potential problems of insisting on contiguous space, but I just have to have it. I have seen how to do this for a 2D array, but apparently I don't understand how to extend the pattern to 3D. When I call the function to free up the memory, free_3d_arr, I get an error:
lowest lvl
mid lvl
a.out(2248,0x7fff72d37000) malloc: *** error for object 0x7fab1a403310: pointer being freed was not allocated
Would appreciate it if anyone could tell me what the fix is. Code is here:
#include <stdio.h>
#include <stdlib.h>
int ***calloc_3d_arr(int sizes[3]){
int ***a;
int i,j;
a = calloc(sizes[0],sizeof(int**));
a[0] = calloc(sizes[0]*sizes[1],sizeof(int*));
a[0][0] = calloc(sizes[0]*sizes[1]*sizes[2],sizeof(int));
for (j=0; j<sizes[0]; j++) {
a[j] = (int**)(a[0][0]+sizes[1]*sizes[2]*j);
for (i=0; i<sizes[1]; i++) {
a[j][i] = (int*)(a[j]) + sizes[2]*i;
}
}
return a;
}
void free_3d_arr(int ***arr) {
printf("lowest lvl\n");
free(arr[0][0]);
printf("mid lvl\n");
free(arr[0]); // <--- This is a problem line, apparently.
printf("highest lvl\n");
free(arr);
}
int main() {
int ***a;
int sz[] = {5,4,3};
int i,j,k;
a = calloc_3d_arr(sz);
// do stuff with a
free_3d_arr(a);
}
Since you are using C, I would suggest that you use real multidimensional arrays:
int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));
This allocates contiguous storage for your 3D array. Note that the sizes can be dynamic since C99. You access this array exactly as you would with your pointer arrays:
for(int i = 0; i < sz[0]; i++) {
for(int j = 0; j < sz[1]; j++) {
for(int k = 0; k < sz[2]; k++) {
a[i][j][k] = 42;
}
}
}
However, there are no pointer arrays under the hood, the indexing is done by the magic of pointer arithmetic and array-pointer-decay. And since a single calloc() was used to allocate the thing, a single free() suffices to get rid of it:
free(a); //that's it.
You can do something like this:
int ***allocateLinearMemory(int x, int y, int z)
{
int *p = (int*) malloc(x * y * z * sizeof(int));
int ***q = (int***) malloc(x * sizeof(int**));
for (int i = 0; i < x; i++)
{
q[i] = (int**) malloc(y * sizeof(int*));
for (int j = 0; j < y; j++)
{
int idx = x*j + x*y*i;
q[i][j] = &p[idx];
}
}
return q;
}
void deallocateLinearMemory(int x, int ***q)
{
free(q[0][0]);
for(int i = 0; i < x; i++)
{
free(q[i]);
}
free(q);
}
I use it and works fine.

double free or corruption 3d array in C

I get a 'double free or corruption' error while freeing up an 3d array. Can anyone please tell me where is the problem in the code? The size of the array is 2*N*N. Value of N here is 100. Even without casting, same result.
Here is the code:
// Mallocing
double ***h = malloc(2 * (sizeof(double**)));
for(i = 0; i < N; i++) {
h[i] = malloc(N * sizeof(double*));
for(j = 0; j < N; j++) {
h[i][j] = malloc(N * sizeof(double));
}
}
// Freeing
for(i = 0; i < N; i++) {
for(j = 0; j < N; j++) {
free(h[i][j]);
}
free(h[i]);
}
free(h);
The program works fine but at the end I get an error 'double free or corruption (!prev): 0x08cd24f8'
Aborted (core dumped).
For the first dimension, you allocate 2 elements:
double ***h = (double***) malloc(2 * (sizeof(double**)));
But you treat it as if it had N elements:
for(i = 0; i < N; i++) {
h[i] = ...
Change outermost loop comparison on allocation and free to:
for(i = 0; i < 2; i++) {
Also don't cast return value of malloc. Also, your code is missing error handling, and will break if allocation fails.
As fas as I can see you allocate 2 items, then fill N of them.
double ***h = (double***) malloc(2 * (sizeof(double**)));
for(i = 0; i < N; i++) {
h[i] = (double**) malloc(N * sizeof(double*));
....
....
}
You're overwriting not allocated space if N>2...
The problem's here:
double ***h = (double***) malloc(2 * (sizeof(double**)));
for(i = 0; i < N; i++) {
// ...
}
You only malloc 2 elements, and iterate over N.
I guess you wanted to have array of size N*N*N, but you ended up with 2*N*N instead.
So this:
double ***h = (double***) malloc(2 * (sizeof(double**)));
Should be:
double ***h = (double***) malloc(N * (sizeof(double**)));
If the value of N = 100 as in your comment then you need to allocate memory to hold N pointer-to-pointer where you have just 2 .
double ***h = malloc(N * (sizeof(double*)));
Don't cast malloc()
As others have pointed out, the specific problem causing the bug is you treating the dimension with 2 elements as if it had N elements.
The core reason for this however, is obfuscation. There are some rules I would strongly recommend you to follow:
Always allocate multi-dimensional arrays as true arrays allocated in adjacent memory. Reference.
Never allocate multi-dimensional arrays as pointer-to-pointer based lookup-tables that are fragmented all over the heap. Not only are they slower and make the code harder to read, they aren't actually arrays. You can't use them together with memcpy() etc.
Unfortunately there are countless of bad C programming teachers and bad books that preach fragmented pointer-to-pointer lookup-tables. So many programmers have to unlearn this, it is frightening...
Never use more than two levels of indirection in your program. There should never be a reason to do so, all it does is to turn your program less readable (Reference MISRA-C:2012 rule 18.5). This is actually known as "three star programming" and it's not a flattering term.
Never cast the result of malloc, because it is pointless to do so.
What you should do:
double (*array)[Y][Z] = malloc( sizeof(double[X][Y][Z]) );
...
free(array);
Example:
#include <stdio.h>
#include <stdlib.h>
#define X 2
#define Y 3
#define Z 4
int main (void)
{
double (*array)[Y][Z] = malloc( sizeof(double[X][Y][Z]) );
double count = 0.0;
for(int x=0; x<X; x++)
{
for(int y=0; y<Y; y++)
{
for(int z=0; z<Z; z++)
{
array[x][y][z] = count++;
printf("%f ", array[x][y][z]);
}
printf("\n");
}
printf("\n");
}
free(array);
return 0;
}
To compile this, you need a compiler which is not older than 16 years.

How to malloc 2D arrays? [duplicate]

This question already has answers here:
Allocating 2-D array in C
(2 answers)
Closed 8 years ago.
I need to create a two dimensional array. Presently I created it as
int a[100][100]
but I need to allocate the memory dynamically using malloc in C language. I used the code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n=6, m=5, i, j;
int **a = malloc(n * sizeof(int *));
for(i = 0; i < m; i++)
a[i] = malloc(m * sizeof(int));
for( i = 1; i <= n; i++ )
{
for( j = 1; j <= m; j++ )
{
scanf("%d %d",&a[i][j]);
}
}
return 0;
}
but now while inputting the elements into the array it shows SEGMENTATION ERROR.
You say in the comments that n is the number of rows. So you need to allocate n rows each of length m. Therefore, the second for loop condition should be i < n. Also, you should check the return value of malloc for NULL in case it fails to allocate memory. I suggest the following change -
long long **a = malloc(n * sizeof(*a));
for(i = 0; i < n; i++)
a[i] = malloc(m * sizeof(*a[i]));
Please note that a multi-dimensional array is not a fundamentally new type. It's simply an array of elements where each element itself is an array (for a 2D array), an array of arrays (for a 3D) array and so on. If you are using C99, you can allocate your array cleanly and succinctly as
int nrow = 4; // number of rows
int ncol = 8; // number of columns
// define arr to be a pointer to an array of ncol ints, i.e.,
// arr is a pointer to an object of type (int[ncol])
int (*arr)[ncol] = malloc(sizeof(int[nrow][ncol]));
// check the result of malloc for NULL
if(arr == NULL) {
printf("malloc failed to allocate memory\n");
// handle it
}
// do stuff with arr
for(int i = 0; i < nrow; i++)
for(int j = 0; j < ncol; j++)
arr[i][j] = i + j;
// after you are done with arr
free(arr);
You should also go through this - How do I work with dynamic multi-dimensional arrays in C?
You have three errors: The first is that you allocate only 5 secondary arrays, but in the input you loop over 6 of them.
The second problem is that array indices are zero-based, i.e. the index start at zero and goes to the size minus one.
The third problem is that you scan for two numbers (why?), but you provide only one destination pointer to scanf.
you just need
long *a = malloc(100*100*sizeof(long));
if you want one single big block of memory.
if you want an array of long* pointers and then each array to be in a separate block of memory go like this:
long **a = malloc(100*sizeof(long*));
for (i=0; i<100; i++) {
a[i] = malloc(100*sizeof(long));
}
This creates 1 array of long* pointers, and then 1 array of 100 longs of each pointer, but I'm not sure now if you say a[10][15] for example if it would calculate position of the element as if its a continuous block. Check that out. :)
If you have C99 use Variable Length Array
#include <stdio.h>
#include <stdlib.h>
int main(void) {
unsigned rows, cols;
printf("Enter rows and columns: ");
fflush(stdout);
scanf("%u%u", &rows, &cols);
int (*a)[cols]; // pointer to VLA
a = malloc(rows * cols * sizeof a[0][0]);
if (a) {
for (unsigned r = 0; r < rows; r++) {
for (unsigned c = 0; c < cols; c++) {
a[r][c] = r*c;
}
}
printf("the element at [4, 2] is %d\n", a[4][2]);
free(a);
}
return 0;
}
Otherwise, you need to calculate the indexing manually.
There are many problems in your code
First, you need long long a[100][100] but you only allocate enough space for ints
a[i] = malloc(m * sizeof(int));
You're also accessing arrays out-of-bound. Indexes start from 0 to array_length-1.
Another problem is that you scanf 2 int values but only provide the address for 1.
scanf("%d %d",&a[i][j]);
You can allocate a 100-element array of pointers, each points to an array of another 100-element array but that's not good because it takes time to do 100 mallocs, and the resulting memory most probably isn't contiguous, which makes it cache unfriendly. There are also a small memory overhead too because the memory allocator must round it up to the nearest block size and this is most probably powers of 2, which may be large as you allocate more and more elements in the first dimension.
You should declare a 1D array of size 100*100 instead. This will be much faster and improve cache coherency. To get the element at a[i][j] just do a[i*WIDTH + j]
long long* a = malloc(WIDTH*HEIGHT*sizeof(long long));
for (i = 0; i < WIDTH*HEIGHT; i++)
{
scanf("%lld ",&a[i]);
}
for (i = 0; i < HEIGHT; i++)
{
for (j = 0; j < WIDTH; j++)
{
printf("%lld ", a[i*WIDTH + j]);
}
printf("\n");
}

Allocate a 2d array in C with one dimension fixed

I want to dynamically allocate 1 dimension of a 2D array (the other dimension is given). Does this work:
int NCOLS = 20;
// nrows = user input...
double *arr[NCOLS];
arr = (double *)malloc(sizeof(double)*nrows);
and to free it:
free(arr)
Not quite -- what you've declared is an array of pointers. You want a pointer to an array, which would be declared like this:
double (*arr)[NCOLS];
Then, you'd allocate it like so:
arr = malloc(nrows * sizeof(double[NCOLS]));
It can then be treated as a normal nrows by NCOLS 2D array. To free it, just pass it to free like any other pointer.
In C, there's no need to cast the return value of malloc, since there's an implicit cast from void* to any pointer type (this is not true in C++). In fact, doing so can mask errors, such as failing to #include <stdlib.h>, due to the existence of implicit declarations, so it's discouraged.
The data type double[20] is "array 20 of double, and the type double (*)[20] is "pointer to array 20 of double". The cdecl(1) program is very helpful in being able to decipher complex C declarations (example).
An example:
#include <stdio.h>
#include <stdlib.h>
#define COLS 2
void func(int (**arr)[COLS], int rows)
{
int i, j;
*arr = malloc(sizeof(int[COLS]) * rows);
printf("Insert number: \n");
for(i = 0; i < rows; i++)
for(j = 0; j < COLS; j++)
scanf("%d", &(*arr)[i][j]);
for(i = 0; i < rows; i++)
for(j = 0; j < COLS; j++)
printf("%d\n", (*arr)[i][j]);
}
int main(void)
{
int (*arr)[COLS];
func(&arr, 2);
free(arr);
return 0;
}
You have to allocate a new array for each element (each element is a pointer to an array) on the first dimension. You can use a loop for that:
for(i = 0; i < NCOLS; i++)
arr[i] = (double *)malloc(sizeof(double)*nrows);
Do the same to free.

Resources