Home > programming > C Tidbit: Arrays of Strings as char**

C Tidbit: Arrays of Strings as char**

February 22nd, 2009

While working further on my crypto assignment this evening, I had a hell of a time working with an array of strings in C. For those of you who know C, a string is really a character pointer (char *), and an array of strings, while often denoted *str[], can also be allocated as a pointer to a pointer of chars (char **). Long story short, after writing a bunch of code that utilizes this, I realized that I didn’t need all those strings and could actually get by with just one temporary variable, so I rewrote my code and got rid of all the code that took me so long to figure out. Because what I learned was useful, I’m writing it here for posterity and hopefully as a decent explanation for anyone else. This isn’t all the code that I wrote, but just snippets big enough to get the gist.

So, when you want to allocate memory for a bunch of (related) strings, you have two choices:

  1. Declare one char pointer (char *) and allocate enough memory for all the strings (and their terminating NUL bytes).
  2. Declare a pointer to a char pointer (char **) and allocate memory for the pointers and strings themselves separately.

My problems arose when I tried to combine these two approaches, by using a char** so I could access my individual strings with array notation (str[i]), but since I knew how much space I’d need ahead of time (but not at compile time), allocating all the memory at once. It makes sense that this didn’t work, since I was actually allocating a lot of space for a ton of pointers, but not actually any memory for the character pointers (i.e. the strings).

Since my explanation is mediocre, here’s a bit of code to explain:

/* Approach 1: one big char pointer */
char *bigstr; // Declare one character pointer, i.e. one string
int length = 72; // Enough space for 8 8-char values plus a NUL byte for each
int i;


bigstr = malloc(sizeof(char) * length);
for (i = 0; i < length; i += 9) { // I know this sucks, and I later fixed it
    fscanf (infile, "%s", &input_strs[i]);
    // or fscanf(infile, "%s", input_strs + i);
}

So, the benefit of the above approach is that you can allocate your memory all at once. The downside is that you have to either access the input_strs[] with the address-of operator (the ampersand) or just shove the pointer in and do pointer arithmetic.

Now, on to the second option:

/* Approach 2: pointer to a pointer */
char **str_array; // Declare a pointer to a pointer, i.e. an array of strings
int length = 8; // Enough space for 8 char pointers
int input_str_size = 9; // Enough space for 8 bytes plus NUL
int i;


str_array = malloc(sizeof(char *) * length);
for (i = 0; i < length; i++) {
    str_array[i] = malloc(input_str_size);
    fscanf (infile, "%s", str_array[i]);
    // or fscanf(infile, "%s", *input_strs + i);
}

The advantage of this second approach, as you can see, is that you can directly apply the array notation without the (possibly confusing) need for the address-of operator. The downside is that you don’t allocate all the memory ahead of time, so it may be slower to allocate small chunks of memory in a loop. This would be the way to go, however, if your strings were of different sizes.

Which of these two paths you choose is up to you, and it really depends on your application. However, just remember the difference between the two, and try not to mix them up like I did!

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Technorati

programming ,

  1. No comments yet.
  1. No trackbacks yet.