Search code examples
cstringmalloccallocdynamic-allocation

Allocate 2D char array malloc or calloc


I've recently decided to brush up my C knowledge (what little of it I have left). I quite quickly realized that the first skill to go cloudy was memory management. Damned.

I decided that the best thing to do, was to write some pointless pointer exercises. The first one was to allocate an array of 4 char arrays, each of which were of variable length.

A simplified version of that code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char **aStr = malloc(4*sizeof(aStr));
    int j = 0;
    int i = 0;
    while(i<sizeof(aStr))
    {
        j = 4 + 2*i;//in my code, length is determined by arguments
        aStr[i] = malloc(j*sizeof(aStr[i]));
        j--;
        strncpy(aStr[i],"RaisinRubarbCarrot"+i,j);
        aStr[i][j] = 0;//just a habbit
        j++;
        printf("ptr@:%p\n\tkey:%d\n\tval:%s\n\tlength:%d (%d)\n\n",*aStr[i],i,aStr[i],j,strlen(aStr[i]));
        i++;
    }
    free(aStr);
    return 0;
}

I felt this to be clunky, and counter-intuitive. Today I remembered my old nemisis: calloc. I then wrote

char **aStr = (char **)calloc(4, sizeof(char *));

and in the loop:

aStr[i] = (char *) calloc(j,sizeof(char *));

I have found code examples that write the last line like so:

aStr[i] = (char *) calloc(j,sizeof(char));//without the asterisk

Question 1: what's the difference, if any?

Question 2: Isn't there another way of allocating an array of strings? the way I see the code now, it feels/looks like I am first allocating 4 pointers to a single char pointer, and then allocating the actual size required for each pointer. That just feels wrong.

Then again I might be wrong about all of this all together, in which case: feel free to bang my head against the wall and point me in the direction of a decent manual I should read before wasting all of your time...


Solution

  • char * and char are two different types, and have different data sizes. A char is always a single byte, so sizeof(char) is always 1. A pointer to char on the other hand, will be 4 bytes on a 32bit system. So if you use sizeof(char*) to allocate space for a string, you'll be allocating much more than you need.

    Using the loop to allocate the individual strings is fine. Assuming a maximum length for your strings, you could just allocate one big block, but that would be clumsy.