Dynamic Allocation of an Array of Strings in C

2019-08-09 15:38发布

问题:

For home-work, I need to define a function that allocate memory to an array of strings (which is into a struct).

The length of each string is given: MAX_WORD_LEN+1 (=10+1) I have to allocate memory for len number of strings, len is recieved in the input.

Struct with the array of strings definition (given):

struct dict{
    int len;
    char (*dict0)[MAX_WORD_LEN+1];
    char (*dict1)[MAX_WORD_LEN+1];
};

I don't understand the declaration char (*dict0)[MAX_WORD_LEN+1];

  • The function declaration is also given:
    void createDict(struct dict* myDict);

This is what I wrote, but I'm not sure it works, and I have a difficult time checking it in the compiler. I also wrote it based on post from this and other websites and do not really understand it:

OPTION 1:

void createDict(struct dict* myDict)
{

    myDict->(*dict0) =  malloc( (myDict->len)*sizeof(char*));
    myDict->(*dict1) = (char**) malloc( (myDict->len)*sizeof(char*));

    for(int i=0;i<(myDict->len);i++)
    {
        (myDict->(*dict0)[i]) = (char*)malloc((MAX_WORD_LEN+1)*sizeof(char));
        (myDict->(*dict0)[i]) = (char*)malloc((MAX_WORD_LEN+1)*sizeof(char));
    }
}

OPTION 2:

(myDict->(*dict0)[MAX_WORD_LEN+1]) = malloc((myDict->len) * sizeof(char*));
(myDict->(*dict1)[MAX_WORD_LEN+1]) = malloc((myDict->len) * sizeof(char*));

Please explain to me...

回答1:

First you need to understand the difference between the following three declarations. For the sake of brevity, assume N is MAX_WORD_LEN+1 to match your sizing:

char data[N];      // array of N chars
char *data[N];     // array of N char *pointers* (i.e. char *)
char (*data)[N];   // pointer to array of N chars

Remember above all else, pointers are variables that hold an "address" and are implementation-defined. Just like an int variable holds the value of an implementation integer, a pointer variable holds an implementation address.

In almost all cases, you can properly malloc() memory for a pointer type using the sizeof() operator with the underlying target dereferenced. There are some cases where this is not intuitive or easily presentable, but the following should help:

// allocates sizeof(Type) block
Type *p = malloc(sizeof(*p));

// allocates N*sizeof(Type) contiguous blocks
//  note: we'll use this style later to answer your question
Type *pa = malloc(N * sizeof(*pa));

This will work no matter what Type is. This is important, because in your case you have a pointer declared as :

char (*dict)[N];

As we already discussed above, this declares a pointer of type (pointer-to-N-chars). Note that no actual memory has been allocated yet. This is just a pointer; nothing more. Therefore, you can safely allocate a single element using the above syntax as:

// allocate single block
char (*dict)[N] = malloc(sizeof(*dict));

But this only accounts for a single entry. You need len entries, so :

// allocate 'len' contiguous blocks each N chars in size
char (*dict)[N] = malloc(len * sizeof(*dict));

Now dict is safely addressable as an array from 0..(len-1). You can copy in your data such as:

strcpy(data[0], "test");
strcpy(data[1], "another test");

So long as the source string does not exceed N-chars (including the zero-terminator), this will work correctly.

Finally, don't forget to free your allocation when finished:

free(dict);

Spoiler

myDict->dict0 =  malloc( myDict->len * sizeof(*(myDict->dict0)));
myDict->dict1 =  malloc( myDict->len * sizeof(*(myDict->dict1)));


回答2:

In the declaration of the structure,

char (*dict0)[MAX_WORD_LEN+1];

means that dict0 is a pointer to a character array of MAX_WORD_LEN + 1 elements i.e. char [11].

To initialize the field of your object, you can consider an example as shown below

void createDict(struct dict* myDict)
{
    myDict->dict0 = &glbarr;
    myDict->dict1 = &glbarr;
}

where glbarr is a global array defined as

char glbarr[MAX_WORD_LEN+1];


回答3:

char (*dict)[MAX_WORD_LEN+1] is a pointer to an array of char[MAX_WORD_LEN+1]. Or you can interpret it as an array of such arrays (a two-dimensional array).

Let's say typedef char MyString[MAX_WORD_LEN+1];.

Then your declaration will look as MyString *dict0; In other words, the dict0 can be a pointer to the first element of an array of MyString. And this is what you should do.

I will not post the detailed solution (your teacher would not be happy with that).

I suggest also that you feel the difference between char (*dict)[10]; and char *dict[10];.