Reputation: 129
Couldn't find any questions on StackOverflow that addresses this question.
I realize that char* arrays don't have to be NULL terminated, but was wondering when you would want it to be?
For example, when debugging my code, I use a lot of printf() to see if my variable is correct at certain stage of the code.
I have an char** values that holds 4 char*, I made the last char* NULL. With NULL terminating, printfs from values[0] to values[3] give me this note: names is just another array that I print right after I finish printing the values array
Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
Testing values1[3]: (null)
Testing names2[0]: PATH
Testing names2[1]: IDIR
Testing names2[2]: LIBDIR
I have an char** with 3 char*, all of which are valid char*. Without NULL terminating, printf from values[0] to values[3] gives me this (names doesn't show)
Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
I think when printf(...., values[3]) would be an undefined behavior, such as printing a garbage value, but as shown in the output above, everything including and after printf(...., values[3]) seems to not have been executed.
Upvotes: 1
Views: 4445
Reputation: 1
In C99 (& POSIX), the only array of char*
which is required to be NULL
terminated is the argv
second argument to main
. Hence your main
function is (or should be) declared as
int main(int argc, char**argv);
and (at least on POSIX systems) it is required (and enforced by the runtime crt0) and you should expect that:
argc
is positiveargv
is an array of argc+1
pointers, each of them being a C string (so ending with a \0
byte)argv[argc]
is required to be the NULL
pointerargv
(i.e. argv[
i]
and argv[
j]
with both i and j being non-negative and less than argc+1
) are not pointer aliases (that is the same pointer value)Of course, some libraries may also have functions whose argument might have similar requirements. That should be documented.
Upvotes: 0
Reputation: 214890
There's a lot of confusion here. First of all:
'\0'
(sometimes called "nul character") at the end of a character array to state where your string ends. It has nothing to do with NULL pointers what so ever. A better name than "null termination" might be zero termination, as that is less confusing.Now as it happens, 0, NULL and '\0'
all give the value zero, so they could in practice be used for the wrong purpose and the code will still work. What you should do, however, is this:
0
for integers.NULL
for pointers.'\0'
to terminate a characer array and thereby making it a C string.Next matter of confusion:
I have an char** values that holds 4 char*
Pointers do not hold values. Arrays hold values. Pointers are not arrays, arrays are not pointers. Pointer-to-pointer is not an array, nor is it a 2D array.
Though in some circumstances, you can get a pointer to the first element from an array.
An array of pointers to strings of variable length can be declared as: char* string_array [N];
. You could iterate through this array by using a pointer-to-pointer, but that's not a good idea. A better idea is to use array indexing: string_array[i]
.
Overall, there exists very few cases where you actually need to use a pointer-to-pointer. Returning a pointer to an allocated resource through a function parameter is the normal use for them. If you find yourself using pointer-to-pointers elsewhere, it is almost a certain indication of bad program design.
For example, one particular case of very wide-spread but 100% incorrect use of pointer-to-pointer is when allocating 2D arrays dynamically on the heap.
when should char** be null terminated?
Never. That doesn't make any sense, as explained above. Your should most likely not use char**
to begin with.
You could however end a character pointer array with NULL, to indicate the end of the array. This is common practice, but don't confuse this with zero termination of strings.
Example:
const char* str_array [] =
{
"hello",
"world",
NULL
};
for(size_t i = 0; str_array[i] != NULL; i++)
{
puts(str_array[i]);
}
Upvotes: 7
Reputation: 129
I got an answer from my TA, as a response to "when should char** be null terminated?" which I find reasonable. It would be cool if there are other reasons to why you would do this.
"This is a good conceptual question, and you can think of it as analogous to why C strings are null-terminated.
Suppose you didn't want to explicitly store the length of an array (because it's extra data for you to manage and pass around, etc). How would you know where the array ends? The NULL at the end acts as a sentinel value so you can simply iterate over it until you reach the magic end-of-array value.
If you have a fixed array size or are storing it in some other way, the NULL end isn't necessary."
Upvotes: 3
Reputation: 134396
As per C11
, chapter §7.21.6.1, fprintf()
, %s
conversion specifier
s
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.
So, you may not pass a NULL
as the argument. It invokes undefined behavior. You cannot predict the behaviour of UB.
What you can do is, put a check on the argument to be != NULL
and then, pass the variable. Something like
if (values[n])
puts(values[n]);
Upvotes: 0
Reputation: 1244
Each string needs to be null terminated. Easy option would be to memset the full array with null (i.e. 0 or '\0').
Alternatively, if you don't want to null terminate, then you need to keep track of the length of the string.
Upvotes: 0