2

I am trying to allocate memory for an array of C strings. I can guarantee that the strings fit within MAX_STRING_LENGTH characters, but I don't know at compile time how many strings will be in the array (this is computed dynamically). When I use the code...

char *strings[MAX_STRING_LENGTH] = malloc( sizeof(char *) * numstrings );

...the compiler complains that this is an invalid initializer. When I use the code...

char strings[MAX_STRING_LENGTH][] = malloc( sizeof(char *) * numstrings );

...the compiler complains about an incomplete element type. What am I doing wrong here, and how can I allocate memory for this array?

Daniel Standage
  • 8,136
  • 19
  • 69
  • 116
  • Of course, I could always allocate memory for a `char **` and then iterate through and allocate a `char *` for each string, but it's that iteration and allocation I'm trying to avoid. – Daniel Standage Jul 24 '12 at 17:55
  • Oh, so you do know the number of strings beforehand (i.e. before the allocation). Then just create a `char **` and iterate as you said. – houbysoft Jul 24 '12 at 17:57
  • @houbysoft By "beforehand" I meant at compile time. I updated the question accordingly. – Daniel Standage Jul 24 '12 at 18:05

4 Answers4

2

With this declaration:

char *strings[MAX_STRING_LENGTH] = malloc(sizeof(char *) * numstrings);

It reads as if you're defining an array of C strings, whose count - not the individual string lengths - is MAX_STRING_LENGTH.

Better to define a **char, like so:

char **strings = malloc(sizeof(char *) * numstrings);

Later in your code, when you're ready to add a string to e.g. slot 5:

strings[5] = malloc(sizeof(char) * MAX_STRING_LENGTH));

or in an init loop such as:

for (i = 0; i < numstrings; i++)
    strings[i] = malloc(sizeof(char) * MAX_STRING_LENGTH);

And, if at some point you need room for more strings, use realloc to grow the initial memory allocation.

pb2q
  • 58,613
  • 19
  • 146
  • 147
2
char (*strings)[MAX_STRING_LENGTH] = malloc(sizeof *strings * num_strings);

will allocate a num_strings x MAX_STRING_LENGTH array of char as a contiguous chunk so that you don't have to do multiple levels of allocation.

strcpy(strings[i], "This is a test");
printf("%s\n", strings[j]);

etc. When you're done you only have to free(strings);.

The main drawbacks with this method are that you may not have enough memory to satisfy the request if num_strings is very large, and that you'll have some internal fragmentation if most of your strings are shorter than MAX_STRING_LENGTH.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Nice. This is closest to my original intent. The two drawbacks you mention were problems I would have had with my original attempt, had it worked, so they are drawbacks I can live with. Thanks! – Daniel Standage Jul 25 '12 at 12:27
1
char **strings;

strings=(char **) malloc(number of strings);

strings[i]=(char *) malloc(MAX_STRING_LENGTH);
alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • 1) The first call disregards the size of the pointer type; 2) you shouldn't cast the return value from malloc() (see http://stackoverflow.com/a/605858/28169). – unwind Jul 24 '12 at 19:24
  • I am used to cast malloc all the time, even if I know that void is automatically converted. However, I see the interesting comment that a program may crash if I forget to include stdlib. Can someone explain why ? – alinsoar Jul 24 '12 at 20:38
1

If it is truly dynamic, then it may need to be something like this:

char **strings = malloc( sizeof(char*) * numstrings );
for ( int i = 0; i < numstrings; i++ )  
    strings[i] = malloc( MAX_STRING_LENGTH );

It is also possible to allocate it all in one chunk (makes freeing it easier) and then assign the individual pointers in the array to computed positions in the allocated buffer. That, though, adds some complexity that may not exceed the benefit.

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110