tags:

views:

515

answers:

6

Lets say we have an array of char pointers

char* array[] = { "abc", "def" };

Now what should be put in the end ?

char* array[] = { "abc", "def", '\0' };

or

char* array[] = { "abc", "def", "\0" };

Though, both works. We only have to put the condition to check the end accordingly

like

array[ index ] != '\0';

or

array[ index ] != "\0";

My question is which one is the better way? Which is used by most programmers?

Edit

Most answers say that NULL is better than '\0' and "\0". But I always thought that

NULL is same as '\0' which is same as 0x0 or 0

Is it wrong?

A: 

Well, technically '\0' is a character while "\0" is a string, so if you're checking for the null termination character the former is correct. However, as Chris Lutz points out in his answer, your comparison won't work in it's current form.

ChrisF
Using `'\0'` is comparing a `char *` to a `char` which is like comparing apples to oranges. Neither is correct, really.
Chris Lutz
Missed that - I'll update my answer
ChrisF
@Chris: <nitpick>using `'\0'` is comparing a `char *` to an `int`</nitpick>
Christoph
@Christoph - that's what Chris Lutz pointed out. Rather than update my answer I pointed my answer at his
ChrisF
+17  A: 

I would end it with NULL. Why? Because you can't do either of these:

array[index] == '\0'
array[index] == "\0"

The first one is comparing a char * to a char, which is not what you want. You would have to do this:

array[index][0] == '\0'

The second one doesn't even work. You're comparing a char * to a char *, yes, but this comparison is meaningless. It passes if the two pointers point to the same piece of memory. You can't use == to compare two strings, you have to use the strcmp() function, because C has no built-in support for strings outside of a few (and I mean few) syntactic niceties. Whereas the following:

array[index] == NULL

Works just fine and conveys your point.

Chris Lutz
Actually, the `char*` comparison probably worked for the OP, since the compiler unified the two identical string literals. I agree that the comparison is meaningless, in principle.
Martin v. Löwis
I know it probably worked, but it is by no means guaranteed to work, and should never be relied upon, and is therefore meaningless. If it works, it works because you have a smart compiler, or because you got lucky.
Chris Lutz
Is NULL not same as '\0'? What I understand is that NULL == '\0' == 0x0.Is is incorrect?
Andrew-Dufresne
Usually NULL is ((void*)0)... though the values are equal, the types are different.
fortran
Nitpick - the first comparison is actually OK - `'\0'` is an integer value of zero, and in this context is evaluated as a null pointer constant. It's not a good idea though, because it conveys a sense of confusion on the part of the author. If you mean `NULL`, say `NULL`.
caf
@caf exactly what i just wanted to write, +1. @Chris, and note that in C, character literals actually have type `int` not `char` (but this wouldn't change its ability to be a null pointer constant - `char` is an integer type too). Fix it and i will +1 u too xD
Johannes Schaub - litb
@litb - Is there any situation where assuming that a character literal is of type `char` instead of `int` will cause a programming error?
Chris Lutz
@Chris, dunno of a real example. But there are theoretical ones... :) A platform where char and int both have 16bits, and where char is unsigned. As a consequence, char would be promoted to unsigned int. Then, `'\0'-1` would become `UINT_MAX` if character constants had type `char`, and it would become `-1` if character constants had type int. (because int is not promoted). And then of course there is still the `sizeof` matter, which will probably give you a different result on most platforms.
Johannes Schaub - litb
I thought unadorned `char` was guaranteed to be signed. Is that not the case?
Chris Lutz
No, that's not the case. `char` is either unsigned or signed. The choice is implementation defined, and what's also important: It's still a distinct type (it's neither signed char, nor unsigned char) :)
Johannes Schaub - litb
Ah. I need to read up on my standards-fu. Thanks for clarifying that.
Chris Lutz
+5  A: 

Of these two, the first one is a type mistake: '\0' is a character, not a pointer. The compiler still accepts it because it can convert it to a pointer.

The second one "works" only by coincidence. "\0" is a string literal of two characters. If those occur in multiple places in the source file, the compiler may, but need not, make them identical.

So the proper way to write the first one is

char* array[] = { "abc", "def", NULL };

and you test for array[index]==NULL. The proper way to test for the second one is array[index][0]=='\0'; you may also drop the '\0' in the string (i.e. spell it as "") since that will already include a null byte.

Martin v. Löwis
I do find it interesting that this problem has two answers that work, but neither is technically correct, and neither works for the reason the OP thinks they do.
Chris Lutz
A: 

The termination of an array of characters with a null character is just a convention that is specifically for strings in C. You are dealing with something completely different -- an array of character pointers -- so it really has no relation to the convention for C strings. Sure, you could choose to terminate it with a null pointer; that perhaps could be your convention for arrays of pointers. There are other ways to do it. You can't ask people how it "should" work, because you're assuming some convention that isn't there.

newacct
The convention is there for variable-length arrays: use NULL as sentinel value.
kaizer.se
+3  A: 

According to the C99 spec,

  • NULL expands to a null pointer constant, which is not required to be, but typically is of type void *
  • '\0' is a character constant; character constants are of type int, so it's equivalen to plain 0
  • "\0" is a null-terminated string literal and equivalent to the compound literal (char [2]){ 0, 0 }

NULL, '\0' and 0 are all null pointer constants, so they'll all yield null pointers on conversion, whereas "\0" yields a non-null char * (which should be treated as const as modification is undefined); as this pointer may be different for each occurence of the literal, it can't be used as sentinel value.

Although you may use any integer constant expression of value 0 as a null pointer constant (eg '\0' or sizeof foo - sizeof foo + (int)0.0), you should use NULL to make your intentions clear.

Christoph
Although to be *really* nit picking, `NULL` is expanded to a null pointer only in case it's defined as `(void*)0` (in which case it's both that and a null pointer constant) :) If it happens to be `0` or similar, then it's only a null pointer constant, which yet has to be converted to a null pointer :)
Johannes Schaub - litb
@litb: fixed````
Christoph
@litb: actually, `'\0'` might not be a valid null pointer constant as it's a character constant (C99 6.4.4.4) and not an integer constant (C99 6.4.4.1); character constants are sometimes called integer character constants, but does that make them an "integer constant expression" as required by C99 6.3.2.3?
Christoph
@Christop 6.6/6 :)
Johannes Schaub - litb
@litb: thx - don't know why I did not search for the term myself
Christoph
A: 

Null termination is a bad design pattern best left in the history books. There's still plenty of inertia behind c-strings, so it can't be avoided there. But there's no reason to use it in the OP's example.

Don't use any terminator, and use sizeof(array) / sizeof(array[0]) to get the number of elements.

Alan
+1 for sizeof array/sizeof array[ 0 ]. But do you think it is good enough reason for not using terminator?
Andrew-Dufresne
this only works if the array is declared in-scope -- if it's passed by pointer then you cannot do `sizeof(array)` and you can only get the length by passing the size via a parameter, or searching for the null terminator.
Carson Myers
I should have been more clear. Pass the number of elements around along-side your array. Safer and more clear than using a terminator.
Alan