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.
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 (). The total size of the sports array is bytes but only bytes is used, bytes is wasted. 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.
Here 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:
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 or .
The 0th element i.e points to the base address of string . Similarly, the 1st element i.e points to the base address of string and so on.
Here is how an array of pointers to string is stored in memory.
In this case, all string literals occupy bytes and bytes are 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 bytes () 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.
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 ().
But the same thing can be done with an array of pointers to strings.
Since each element of array is a pointer to or , 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:
When the compiler sees the above statement it reserves bytes of memory () to store pointers of type , but it doesn't allocation any memory for a string literal. At this point, all the elements of array contain garbage values and may be pointing to anywhere in the memory. This means the following operations are invalid.
Every now and then I see people writing C++ code containing heresy in the vein of the following:
|char* foo ="bar";|
char * foo = "bar";
This is no more legal C++ than
|constint qux =42;int* quux =&qux;|
const int qux = 42; int * quux = &qux;
It is not undefined, unspecified or implementation defined! It is simply illegal (and conveys false intent: char* implies modifiable string). It should simply not compile, though right now all the major compilers let you get away with such a conversion – but they may (and should) stop that at any time.
It is valid in C (C89 through C11), although assigning to a string literal is undefined behaviour there. C++, however, has deprecated this conversion since C++98.
C++03 §4.2/2 (conv.array/2)
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]
In fact, the original proposal would be old enough to buy alcohol around the world this year, USA included! In my opinion, more than enough time has passed to phase out that “feature”. The C++ Standards Committee seems to agree, as C++11 doesn’t list such conversion at all (conv.array has only one sub point) and, in Annex C, says the following:
C.1.1 Clause 2: lexical conventions [diff.lex]
char* p = “abc”; // valid in C, invalid in C++
In C++, we’re years past writing such code (I hope). If you need a modifiable string, initialize an array or use std::string:
|char foo="bar";// ok std::string qux ="quux";// ok|
char foo = "bar"; // ok std::string qux = "quux"; // ok
and if you don’t need to modify, for the sake of your co-workers (if not your own), don’t break const-correctness and use:
|charconst* foo ="bar";// ok|
char const * foo = "bar"; // ok