Array of Pointers to Strings in C

In the last chapter, we have learned how we can use an array of strings or 2-D array of characters. It may appear to you whenever you need to store more than one string then an array of strings is the way to go, unfortunately, this is not the case. Consider the following example.

char sports[5][15] = {
                         "golf",
                         "hockey",
                         "football",
                         "cricket",
                         "shooting"
                     };

sports array is stored in the memory as follows:

As you can see not all strings are long enough to fill all the rows of the array, that's why compiler fills these empty spaces (highlighted using light grey color) with the null characters ('\0'). The total size of the sports array is 75 bytes but only 34 bytes is used, 41 bytes is wasted. 41 bytes may not appear much but in a large program, a considerable amount of bytes would be wasted. What we need is a jagged array: A 2-D array whose rows can be of different length. C doesn't provide jagged arrays but we can simulate them using an array of pointer to a string.

Array of pointers to strings

An array of pointers to strings is an array of character pointers where each pointer points to the first character of the string or the base address of the string. Let's see how we can declare and initialize an array of pointers to strings.

char *sports[5] = {
                      "golf",
                      "hockey",
                      "football",
                      "cricket",
                      "shooting"
                  };

Here sports is an array of pointers to strings. If initialization of an array is done at the time of declaration then we can omit the size of an array. So the above statement can also be written as:

char *sports[] = {
                     "golf",
                     "hockey",
                     "football",
                     "cricket",
                     "shooting"
                 };

It is important to note that each element of the sports array is a string literal and since a string literal points to the base address of the first character, the base type of each element of the sports array is a pointer to char or char*.

The 0th element i.e arr[0] points to the base address of string "golf". Similarly, the 1st element i.e arr[1] points to the base address of string "hockey" and so on.

Here is how an array of pointers to string is stored in memory.

34 + 20 =54

In this case, all string literals occupy 34 bytes and 20 bytes is occupied by the array of pointers i.e sports. So, just by creating an array of pointers to string instead of array 2-D array of characters we are saving 21 bytes (75-54=21) of memory.

It is important to emphasize that in an array of pointers to strings, it is not guaranteed that the all the strings will be stored in contiguous memory locations. Although the characters of a particular string literal are always stored in contiguous memory location.

The following program demonstrates how to access strings literal in the array of pointers to string and in the process prints the address of each string literal.

#include<stdio.h>
#include<string.h>
int factorial(int );

int main()
{
    int i = 1, *ip = &i;

    char *sports[] = {
                         "golf",
                         "hockey",
                         "football",
                         "cricket",
                         "shooting"
                     };

    for(i = 0; i < 5; i++)
    {
        printf("String = %10s", sports[i] );
        printf("\tAddress of string literal = %u\n", sports[i]);
    }

    // signal to operating system program ran fine
    return 0;
}

Expected Output:

String = golf Address of string literal = 4206592
String = hockey Address of string literal = 4206597
String = football Address of string literal = 4206604
String = cricket Address of string literal = 4206613
String = shooting Address of string literal = 4206621

In the last chapter, we have learned that we can't assign a new string to a 2-D array of characters using assignment operator (=).

char games[3][10] = {
                        "roadrash",
                        "nfs",
                        "angrybirds"
                    };

games[0] = "hitman"; // wrong

But the same thing can be done with an array of pointers to strings.

char *games[3] = {
                     "roadrash",
                     "nfs",
                     "angrybirds"
                 };

games[0] = "hitman"; // ok

Since each element of games array is a pointer to char or char* , it can point to any string literal assigned to it.

Some invalid operation on an array of pointers to strings

Let's discuss some operations we can't perform directly in an array of pointers to string. Consider the following example:

char *top_games[5];

When the compiler sees the above statement it reserves 20 bytes of memory (4*5) to store 5 pointers of type char, but it doesn't allocation any memory for a string literal. At this point, all the elements of top_games array contain garbage values and may be pointing to anywhere in the memory. This means the following operations are invalid.

scanf("%s", top_games[0]); // invalid
strcpy(top_games[0], "mario"); // invalid
gets(top_games[0]); // invalid
strcat(top_games[0], "needforspeed"); // invalid