user3876042
user3876042

Reputation: 15

Dynamic Memory Allocation for 2D Arrays in 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?

Upvotes: 1

Views: 5101

Answers (4)

nitin aditya
nitin aditya

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

ad absurdum
ad absurdum

Reputation: 21363

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

Upvotes: 2

RoadRunner
RoadRunner

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

user7551751
user7551751

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

Related Questions