How to properly dynamically allocate array in C? - c

When allocating array in C, what is the difference between the below two -
int n;
scanf("%d",&n);
int array[n];
And
int *array = (int *)malloc(sizeof(int)*n);
I know that the second one is dynamic allocation of array, which gets allocated from heap. But I am unable to figure out how the first method works. Does it allocate array on runtime, after getting the value for n? And which one should I be using?

Related

C - multidimensional array memory allocation based on user input

I have seen the following declaration of two dimensional array.
int arr[][3] = { {1,2,3}, {4,5,6}};
My question is how can I allocate following multidimensional array in run time based on user input of first dimension?
#define M 10
#define N 15
int arr[][M][N]
Start by declaring a pointer suitable for accessing the array:
int (*array)[M][N];
Then allocate memory for the array based on the user input:
array = malloc(P * sizeof(*array)); // P is the value obtained from the user
Then use the pointer as if it was a 3D array:
array[x][y][z] = 42;
Don't forget to free the memory when you're done with it.
C allows variable-length arrays. So after reading the first dimension from the user, you can declare the array with that size.
int n;
printf("How big is it? ");
scanf("%d", &n);
int arr[n][M][N];

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.

Allocating 2D array with pointer to fixed-size array

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

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

initializing an array using a function in C

I am doing an assignment for class and I thought I would bug you all with a question:
So the purpose of the program is for the user to enter the size of the array and then initialize it with some data. Max size is 20. My issue is that the array crashes when the sets the size beyond 14 and tries to initialize it. So forexample, if it sets the size as 20, it accepts it, but when I try to initialize it, it crashes. I have no idea what I am doing. your help is much appreciated.
Thank you very much,
Essi
int main ()
{
int sizeOfArray = 0; //size Of Array
float myArray[sizeOfArray];
//I have a piece a line or two of code that asks the user for the size of the
array
printf("Let's Initialize an array of size %d!!\n", sizeOfArray);
do
{
printf("Enter array element %d : ", initCounter+1);
myArray[initCounter] = userInitArray();
initCounter++;
}while (initCounter < sizeOfArray);
}
float userInitArray()
{
float num;
scanf("%f", &num);
return num;
}
These two lines
int sizeOfArray = 0; //size Of Array
float myArray[sizeOfArray];
Create an empty array. So whatever you try to store in this array later on is access out of bounds and invokes undefined behavior. The fact that your program crashes on 14th call is simply luck. It could have crashed on the first one just as well.
int sizeOfArray = 0; //size Of Array
float myArray[sizeOfArray];
Your array is created here with a size of zero. It doesn't magically expand when you later increase sizeOfArray. You need to get the size variable set first (from your 'line or two of code' user input) then create the array based on that.
You may also want to impose some sensible upper limit on your array size so you don't blow up your stack when trying, for example, to create a one-billion-entry array :-)
You have a (variable-length) array of size zero. You need to first ask for the size, and then allocate the array. Otherwise any attempts to assign to array elements would result in undefined behaviour.
You could do :
int sizeOfArray; //size Of Array
printf("tell me the size of the array");
scanf("%d",&sizeOfArray);
float myArray[sizeOfArray]; // not a good practice
The right way to do it would be:
int sizeOfArray; //size Of Array
float *myArray;
printf("tell me the size of the array");
scanf("%d",&sizeOfArray);
myArray=malloc(sizeof(float)*sizeOfArray);
You may use the pointer as a common array then.
and call like this: myArray[3] = doSomething();
EDIT Note that since you already know the max size you could avoid doing dynamic allocations listed above:
#Define MAXSIZE 20
int main ()
{
int sizeOfArray; //size Of Array
float myArray[MAXSIZE];
printf("tell me the size of the array\n");
scanf("%d",&sizeOfArray);
printf("\nLet's Initialize an array of size %d!!\n", sizeOfArray);
do
{
printf("Enter the element at myArray[%d] : ", initCounter+1);
myArray[initCounter] = userInitArray();
initCounter++;
}while (initCounter < sizeOfArray);
}
float userInitArray()
{
float num;
scanf("%f", &num);
return num;
}
Probably this last option is what your teacher is actually looking for.
You need to read sizeOfArray before you allocate myArray dynamically like this:
float * myArray = malloc(sizeOfArray * sizeof(float));
This is allocating sizeof(float) * sizeOfArray bytes of memory on heap and assigning address of allocated memory to myArray.
This is maybe hard to understand about arrays in C, they are really just pointers into memory - in your program the array myArray is allocated statically on stack and is of size 0. You cannot add any elements to it or assign to any index, it will not grow, its forewer 0 float elements long. Best thing that can happen to your program in this case is that it will crash. Worst case, it will not crash and strange things will happen;
You really should read something about memory allocation/management in C.
I think you forget to add function prototype in the beginning of your program (before main).
And also
int sizeOfArray = 0; //size Of Array
float myArray[sizeOfArray];
is wrong.
As you are using variable length array (valid in C99), you can do it as
int sizeOfArray; //size Of Array
printf("Let's Initialize an array of size %d!!\n", sizeOfArray);
float myArray[sizeOfArray];
dynamic arrays are not supported in C or C++.
Change your array to:
float* myAraray;
//later when you have the size , allocate it:
myArray = (float*)malloc(arrSize * sizeof(float));

Resources