Reputation: 15
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?
Upvotes: 1
Views: 5101
Reputation: 139
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
Upvotes: 0
Reputation: 21363
Allocating for an array of nrows
pointers to char
, and then separately allocating for nrows
arrays of ncols
char
s 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
char
s. 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
Upvotes: 2
Reputation: 26335
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.
Upvotes: 4
Reputation:
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.
Upvotes: 1