Is it mandatory to give '\0' for initialization of character arrays?

Viewed 720

Please see the code:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char name[10] = {'L','e','s','s','o','n','s'}; // did not add `\0`
    char c;

    for (int i = 0; name[i] != '\0'; i++)
    {
        c = name[i];
        printf("%c", c);
    }

    return 0;
}

I did not give \0 at the end, but still it works.

My question: Is \0 added automatically in the above case?

EDIT: What happens in these cases:

  1. char name[7] = {'L','e','s','s','o','n','s'};
  2. char name[8] = {'L','e','s','s','o','n','s'};

I apologize for editing the question.

6 Answers

In C, partially initialized arrays of any type are 0-initialized for the rest. So,

int foo[5] = {1, 2, 3};

will initialize foo with {1, 2, 3, 0, 0}. So, when you don't add '\0' to the end, not only will the end be '\0' (assuming the array is large enough to fit it), but all remaining elements of the array will be '\0'.

If your array isn't large enough to fit the null terminator, then it won't be added, nor should the value even matter. Reading past the end of an array is undefined behavior, which can lead to segfaults, garbage data, or worse.

Is \0 added automatically in the above case?

Yes. In fact, in your first case (where the array length is specified as 10), all three array elements that you have not explicitly initialized will be default initialized to zero.

From cppreference:

All array elements that are not initialized explicitly are zero-initialized.

Or, from this Draft C11 Standard:

6.7.9 Initialization
...
21 If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.


The above is also true for the case in which you have declared char name[8] (but there will only be one added '\0', in that case).

However, for the case of char name[7] = {'L','e','s','s','o','n','s'};, then you have undefined behaviour - the value of the byte at the memory location immediately following your array could be anything (including zero).

Is it mandatory to give '\0' for initialization of character arrays?

No, it is not.

On one hand, it is perfectly valid for an array of char or any other character type not to contain any element with value 0. However, such an array does not contain a string, and passing a pointer (in)to it to any function relying on you to pass a string results in undefined behavior. That may sometimes manifest as if the array were terminated, but it is not safe to assume that it will do so.

On the other hand, if you declare an array with an initializer that explicitly initializes only some of its elements, then the other elements are implicitly initialized. For elements of type char, that takes the form of initialization to 0. Note well that this behavior is associated with initializers, not assignment.

As applied to your code, then, when array name is declared with dimension 10 and the initializer provides only seven elements, the last three elements take the initial value zero. It is equivalent to this:

    char name[10] = {'L','e','s','s','o','n','s', 0, 0, 0};

... or this:

    char name[10] = {'L','e','s','s','o','n','s', '\0', '\0', '\0'};

... or even this:

    char name[10] = "Lessons";

... among other possibilities.

EDIT: What happens in this cases :

  1. char name[7] = {'L','e','s','s','o','n','s'};

All array elements are explicitly initialized by the given initializer. The array contents are not null-terminated, and thus do not constitute a string. Undefined behavior results from any attempt to use them as if they were a string.

  1. char name[8] = {'L','e','s','s','o','n','s'};

One array element is not explicitly initialized, so it is implicitly initialized to 0. If the intention is that name should have exactly the right number of elements to contain the specified characters plus a terminator, then that is more clearly and safely expressed as

char name[] = "Lessons"; // Array dimension computed automatically

Is it mandatory to give '\0' for initialization of character arrays?

No, not in general.

Yet if code needs the initialized character array to be considered a string, then a null character is needed somehow: explicitly or implicitly.


char name[10] = {'L','e','s','s','o','n','s'}; 

My question : Is \0 added automatically in the above case?

Yes. There are no partial initializations. 7 of the 10 elements are explicitly initialized. If code only explicitly partially initializes an object, "all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration." C17dr § 6.7.9 19

"If an object that has static or thread storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;
— if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; C17dr § 6.7.9 10


EDIT: What happens in this cases :
char name[7] = {'L','e','s','s','o','n','s'};
char name[8] = {'L','e','s','s','o','n','s'};

name[7] is as coded. No null character exist in name[] so the character array is not a string.

name[8] is as if {'L','e','s','s','o','n','s', 0} was coded. Since it contains a null character, name[] is also a string.


The below all initial nameX[] to the same value:

char name1[10] = {'L', 'e', 's', 's', 'o', 'n', 's'};
char name2[10] = {'L', 'e', 's', 's', 'o', 'n', 's', 0};
char name3[10] = {'L', 'e', 's', 's', 'o', 'n', 's', '\0'};
char name4[10] = {'L', 'e', 's', 's', 'o', 'n', 's', 0, 0, 0};
char name5[10] = {[0] = 'L', [1] = 'e', [2] = 's', [3] = 's', [4] = 'o', [5] = 'n', [6] = 's'};
char name6[10] = {[1] = 'e', [2] = 's', [3] = 's', [4] = 'o', [5] = 'n', [6] = 's', [0] = 'L'};
char name7[10] = {[1] = 'e', [3] = 's', [2] = name7[3], [4] = 'o', [5] = 'n', [6] = 's', [0] = 'L'};
char name8[10] = "Lessons";
char name9[10] = "Lessons\0";

I did not give \0 at the end, but still it works.

That's because you invoked undefined behavior. On result of UB is that it appears to work properly.

You don't have to explicitly add the '\0' terminator if you leave room for it.

Your original code was

char name[7] = {'L','e','s','s','o','n','s'}; // did not add `\0`

There's no room for a terminating '\0'.

Per 6.7.9 Initialization, paragraph 21 of the C11 standard:

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

Simple answer of your question is yes. '\0' is added when your string(char array) ends. If you don't want characters after some character then you can add '\0' explicitly after that character.

Related