Dynamic Memory Allocation for 2D Arrays in C - c

I'm reading about dynamic memory allocation for 2D arrays, and I'm looking at this example:
int nrows = 2;
int ncols = 5;
char **pvowels = malloc(nrows * sizeof(char));
pvowels[0] = malloc(ncols * sizeof(char));
pvowels[1] = malloc(ncols * sizeof(char));
My understanding is that the 2nd and 3rd malloc both allocate memory the size of 5 chars and pvowels[0] and pvowels[1] point to each, but I'm having trouble understanding the first malloc.
The first malloc looks like it allocates memory the size of 2 chars, and uses it to store the two pointers. But isn't a char only 256 possible values, and pointers can go up to billions? So if it's allocating memory for storing pointers, doesn't it need to be bigger than chars?

Firstly, your first malloc() is incorrect. Using nrows * sizeof(char) only allocates 2 bytes, whereas you need 2 rows of char* pointers. You have to allocate like this instead:
char **pvowels = malloc(nrows * sizeof(char*));
Or:
char **pvowels = malloc(nrows * sizeof(*pvowels));
Also note that char **pvowels is not a 2D array, but simply a pointer to a char pointer. If you were using a 2D array, such as char pvowels[][], you wouldn't need to dynamically allocate pointers on the heap. You could also just use a 2D array for your problem, such as char pvowels[2][5], as ncols and nrows seems to be fixed in this case.
Secondly, your allocations for pvowels[0] and pvowels[1] will only make space for 4 valid characters, such as "abcd", because 1 space is needed for the null terminating character \0. You should write instead:
pvowels[0] = malloc(ncols+1); /* +1 for '\0' */
pvowels[1] = malloc(ncols+1);
Note: sizeof(char) is always 1, so their is no need to include it. You should also check that malloc() returned NULL or not.

Allocating for an array of nrows pointers to char, and then separately allocating for nrows arrays of ncols chars has a disadvantage, in that the separate memory allocations are not guaranteed to be contiguous in memory. This fragmentation can lead to performance penalties.
A better approach is to allocate enough memory to hold a 2d array, and assign the resulting pointer to a pointer to an array of ncols chars. As shown here, this approach does rely on VLA's, but these have been a part of C since C99. This has the advantage of allocating memory at once, with only one allocation to free.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t nrows = 2;
size_t ncols = 5;
/* Allocate space for a 2d array */
char (*pvowels)[ncols] = malloc(sizeof (char[nrows][ncols]));
/* Another alternative */
// char (*pvowels)[ncols] = malloc(nrows * ncols);
if (pvowels == NULL) {
fprintf(stderr, "Unable to allocate memory\n");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < nrows; i++) {
for (size_t j = 0; j < ncols; j++) {
pvowels[i][j] = 'a' + i * ncols + j;
}
}
for (size_t i = 0; i < nrows; i++) {
for (size_t j = 0; j < ncols; j++) {
printf("%5c", pvowels[i][j]);
}
putchar('\n');
}
free(pvowels);
return 0;
}
Program output:
a b c d e
f g h i j

char **pvowels is a pointer to a pointer, meaning it behaves like an array declared like this:
char * pvowels[a number];
So basically, pointers to chars, and not pointers are being assigned in the example you provided.

A simple and easy to understand code:(Using just a single pointer to store and access)
#include<stdio.h>
#include<stdlib.h>
int main(){
int *a,n,r,c,i,j;
scanf("%d",&n);
r=c=n;
a=(int *)malloc(r*c*sizeof(int));
for(i=0;i<r;i++)
{
for(j=0;j<c;j++){
scanf("%d",(a+i*c+j));
}
}
for(i=0;i<r;i++)
{
for(j=0;j<c;j++){
printf("%d",*(a+i*c+j));
}
}
}
References: geeksforgeeks.org

Related

how to allocate arrays (in array of pointers) C -- can it be done in one line? with malloc

is there a simple one liner I can use in C to allocate arrays in (pointer of arrays)
This line creates 10 pointers of arrays
char *out[10];
I can't do this
char *out[100]=(char[10][100])malloc(sizeof(char)*10*100);
error: cast specifies array type
same error with
char *out[10]=(char*[10])malloc(sizeof(char)*10*100);
do I need to do it in loop like this
int main()
{
char *out[10];
int x=0;
while(x<10)
{
*(out+x)=malloc(sizeof(char)*100);// is this line correct?
x++;
}
*out[0]='x';
printf("%c\n",out[0][0]);
free(out);
return 0;
}
but this cause warning that
req.c:75:3: warning: attempt to free a non-heap object ‘out’ [-Wfree-nonheap-object]
75 | free(out);
so do I need to allocate and free each array in (array of pointers) in loop
Can't I do allocation and free arrays in array of pointer in one line instead of loop?
or is there anything thing in my loop wrong too
To allocate an array of pointers to strings, you need to do:
char** out = malloc(sizeof(char*[10]));
The whole point of using this form is that each pointer in that array of pointers can be allocated with individual size, as is common with strings. So it doesn't make sense to allocate such with a "one-liner", or you are using the wrong type for the task.
In case you don't need individual sizes but are rather looking for a char [10][100] 2D array with static size, then the correct way to allocate such is:
char (*out)[100] = malloc(sizeof(char[10][100]));
You can allocate the full array in one single step and have pointers inside that array:
char *out[10];
data = malloc(100); //sizeof(char) is 1 by definition
for (int x=0; x<10; x++) {
out[i] = data + x * 10;
}
*out[0] = 'x';
printf("%c\n",out[0][0]);
free(data); // you must free what has been allocated
int i;
char** out = (char**)malloc(sizeof(char*)*10);
for(i = 0; i<10;i++)
out[i] = (char*)malloc(sizeof(char)*100);
out[1][1] = 'a';
OR with same dimensions
#include <stdio.h>
#include <stdlib.h>
void main()
{
int r = 10, c = 100; //Taking number of Rows and Columns
char *ptr, count = 0, i;
ptr = (char*)malloc((r * c) * sizeof(char)); //Dynamically Allocating Memory
for (i = 0; i < r * c; i++)
{
ptr[i] = i + 1; //Giving value to the pointer and simultaneously printing it.
printf("%c ", ptr[i]);
if ((i + 1) % c == 0)
{
printf("\n");
}
}
free(ptr);
}

How to ensure a 2D array is allocated contigously in memory

I am sending a 2D array over MPI and for this to work correctly the array needs to be contiguously allocated in memory.
I am allocating it as follows:
int **array;
array = malloc(size1 * sizeof( *(array) );
for (int k = 0; k < size1; k++)
array[k] = malloc(size2 * sizeof(**(array));
Then I would like to use:
MPI_Send(array, size1*size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);
How can I ensure the array is allocated contiguously?
Currently I am trying this:
for (int k = 0; k < size1; k++)
MPI_Send(array[k], size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);
which leads to a seg fault later in an unrelated part of the program. However if I send the elements 1 by 1 it works.
How to ensure a 2D array is allocated contiguously in memory
Allocate in one step.
Example uses C99 code which supports variable length arrays. Here a pointer to a VLA is used.
// ptr is a pointer to a 2D array
int (*ptr)[size1][size2] = malloc(sizeof *ptr);
(*ptr)[0][0] = 1; // One corner of the 2D array
(*ptr)[size-1][size-1] = 2; // Opposite corner of the 2D array
I'll look into sample MPI() code later.
Use:
int (*array)[size2] = malloc(size1 * sizeof *array);
if (!array) Handle error…
If size2 is not a constant and your C implementation does not support variable length arrays, then use:
int *array = malloc(size1 * size2 * sizeof *array);
if (!array) Handle error…
In this case, you will have to use manual address arithmetic to access array elements. Instead of array[i][j], use array[i*size2 + j].
You can not ensure that by using sequential calls to malloc(). What you can do instead, you can allocate from the beginning malloc(size1 * size2) space in the memory, then you can split your allocated buffer how you desire. You can now say that array[i] is in fact array[i * size2] in the memory.
The correct way is to allocate the memory for the 2D array in on single operation. Then as arrays are not really first class citizens in C, not speaking of multi-dimensional arrays, you will have to allocate memory for an array of pointers and make its elements points to the beginning of each row:
int *mem = malloc(sizeof(*mem) * size1 * size2);
int **array = malloc(size1 * sizeof(*array));
for (int k = 0; k < size1; k++) {
array[k] = mem + k * size2 * sizeof(*mem);
}
This will ensure contiguous allocation when it matters for passing the array to routine expecting that, and still allow to access the elements as array[i][j];

Setup a 2D array, change size later - C

Is it possible to declare a 2D array in C, then set its size later on? I know in C you have to deal with memory and such, but I cannot find answer to this question despite all my searching.
My current example is..
int boardsize, linewin;
char array[1][1];
//boardsize is set within here.
array = [boardsize][boardsize];
With C you will need to do your own dynamic array management using pointers.
See the following articles on how to go about doing so using an allocated memory area.
Malloc a 2D array in C
Using malloc for allocation of multi-dimensional arrays with different row lengths
Since you are looking to modify these, you may also need to use the realloc() function or the free() function to release allocated memory.
For information about using the realloc() function look at the following stack overflow.
Realloc double 2D array in C
two-dimensional dynamic array (realloc in c)
EDIT - Adding an example
Here are two functions to malloc() a two dimensional array and to realloc() a two dimensional array. You could actually just use the realloc() version if you pass a NULL pointer to realloc2dCArray() for the memory area to be reallocated.
What I have tried to do is to use a single malloc() and realloc() for all of the memory needed so that you can free() the memory with a single call to free().
char **malloc2dCArray (int nRows, int nCols)
{
// use a single malloc for the char pointers to the first char of each row
// so we allocate space for the pointers and then space for the actual rows.
char **pArray = malloc (sizeof(char *) * nRows + sizeof(char) * nCols * nRows);
if (pArray) {
// calculate offset to the beginning of the actual data space
char *pOffset = (char *)(pArray + nRows);
int i;
// fix up the pointers to the individual rows
for (i = 0; i < nRows; i++) {
pArray[i] = pOffset;
pOffset += nCols;
}
}
return pArray;
}
char **realloc2dCArray (char **pOld, int nRows, int nCols)
{
// use a single realloc for the char pointers to the first char of each row
// so we reallocate space for the pointers and then space for the actual rows.
char **pArray = realloc (pOld, sizeof(char *) * nRows + sizeof(char) * nCols * nRows);
if (pArray) {
// calculate offset to the beginning of the actual data space
char *pOffset = (char *)(pArray + nRows);
int i;
// fix up the pointers to the individual rows
for (i = 0; i < nRows; i++) {
pArray[i] = pOffset;
pOffset += nCols;
}
}
return pArray;
}
To use these functions you would do something like the following:
char **pChars = malloc2dCArray (16, 8);
int i, j;
for (i = 0; i < 16; i++) {
for (j = 0; j < 8; j++) {
pChars[i][j] = 0;
}
}
To do a realloc() you will want to check that the realloc() worked so use a temporary variable and check for NULL before using it.
{
char **pChars2 = realloc2dCArray (pChars, 25, 8);
if (pChars2) pChars = pChars2;
}
You could also just use the realloc() version if you provide a NULL pointer since realloc() will do a malloc() if the pointer to the memory to realloc() is NULL.
I did some testing of this using a debugger and it looks like it is working to me.

Freeing a 2-d char array

After using this function to allocate a 2-d array:
char** make_matrix(int M, int N)
{
char** MAT = (char**)malloc(M * sizeof(char));
for (int i = 0; i < M; i++)
{
MAT[i] = (char*)malloc(N * sizeof(char));
}
return MAT;
}
I found that trying to free(M[0]) causes an assertion failure. All that I can find relating to freeing 2-d arrays use int instead of char. Yet replace every char with int above and the assertion failure disappears. Why is this, and how can I then free the entire 2-d array?
You are allocating too little memory for MAT. Change relevant line to:
char** MAT = (char**)malloc(M * sizeof(char*));
This is because MAT is array of pointers, not characters. Since your code did not allocate enough memory, it was likely writing outside of array bounds and corrupting memory.
It could work with integers because they are bigger, so with some luck you could have been allocating just enough memory (at least on 32 bit machine).
The first malloc call is M * sizeof(char) instead of sizeof(char *). The sizeof(char) would be 1 byte, the size of a char* is likely 4 bytes.
Edit: I see someone beat me to the punch. Accept the other guy's answer.
You should iterate through all the rows of the matrixes and free them first, and then finally the MAT
something like this:
void free_matrix(int M)
{
for (in i = 0; i < M; i++)
{
free(MAT[i]);
}
free(MAT);
}
To release the space (assuming it is correctly allocated), you need a call to free() corresponding to each call to malloc().
void destroy_matrix(char **MAT, int M)
{
for (int i = 0; i < M; i++)
free(MAT[i]);
free(MAT);
}
Your code works when you replace char with int because sizeof(int) == sizeof(int *) on your (32-bit) system. It's largely by coincidence; you'd be in trouble again on a 64-bit system.

Using malloc for allocation of multi-dimensional arrays with different row lengths

I have the following C code :
int *a;
size_t size = 2000*sizeof(int);
a = malloc(size);
which works fine. But if I have the following :
char **b = malloc(2000*sizeof *b);
where every element of b has different length.
How is it possible to do the same thing for b as i did for a; i.e. the following code would hold correct?
char *c;
size_t size = 2000*sizeof(char *);
c = malloc(size);
First, you need to allocate array of pointers like char **c = malloc( N * sizeof( char* )), then allocate each row with a separate call to malloc, probably in the loop:
/* N is the number of rows */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }
for ( i = 0; i < N; i++ )
{
/* x_i here is the size of given row, no need to
* multiply by sizeof( char ), it's always 1
*/
if (( c[i] = malloc( x_i )) == NULL )
{ /* error */ }
/* probably init the row here */
}
/* access matrix elements: c[i] give you a pointer
* to the row array, c[i][j] indexes an element
*/
c[i][j] = 'a';
If you know the total number of elements (e.g. N*M) you can do this in a single allocation.
The typical form for dynamically allocating an NxM array of type T is
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * M);
}
}
If each element of the array has a different length, then replace M with the appropriate length for that element; for example
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * length_for_this_element);
}
}
Equivalent memory allocation for char a[10][20] would be as follows.
char **a;
a=malloc(10*sizeof(char *));
for(i=0;i<10;i++)
a[i]=malloc(20*sizeof(char));
I hope this looks simple to understand.
The other approach would be to allocate one contiguous chunk of memory comprising header block for pointers to rows as well as body block to store actual data in rows. Then just mark up memory by assigning addresses of memory in body to the pointers in header on per-row basis. It would look like follows:
int** 2dAlloc(int rows, int* columns) {
int header = rows * sizeof(int*);
int body = 0;
for(int i=0; i<rows; body+=columnSizes[i++]) {
}
body*=sizeof(int);
int** rowptr = (int**)malloc(header + body);
int* buf = (int*)(rowptr + rows);
rowptr[0] = buf;
int k;
for(k = 1; k < rows; ++k) {
rowptr[k] = rowptr[k-1] + columns[k-1];
}
return rowptr;
}
int main() {
// specifying column amount on per-row basis
int columns[] = {1,2,3};
int rows = sizeof(columns)/sizeof(int);
int** matrix = 2dAlloc(rows, &columns);
// using allocated array
for(int i = 0; i<rows; ++i) {
for(int j = 0; j<columns[i]; ++j) {
cout<<matrix[i][j]<<", ";
}
cout<<endl;
}
// now it is time to get rid of allocated
// memory in only one call to "free"
free matrix;
}
The advantage of this approach is elegant freeing of memory and ability to use array-like notation to access elements of the resulting 2D array.
If every element in b has different lengths, then you need to do something like:
int totalLength = 0;
for_every_element_in_b {
totalLength += length_of_this_b_in_bytes;
}
return malloc(totalLength);
I think a 2 step approach is best, because c 2-d arrays are just and array of arrays. The first step is to allocate a single array, then loop through it allocating arrays for each column as you go. This article gives good detail.
2-D Array Dynamic Memory Allocation
int **a,i;
// for any number of rows & columns this will work
a = malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
*(a+i) = malloc(cols*sizeof(int));
malloc does not allocate on specific boundaries, so it must be assumed that it allocates on a byte boundary.
The returned pointer can then not be used if converted to any other type, since accessing that pointer will probably produce a memory access violation by the CPU, and the application will be immediately shut down.

Resources