0
int main()
{
    char c1[5]="abcde";
    char c2[5]={'a','b','c','d','e'};

    char *s1 = c1;
    char *s2 = c2;

    printf("%s",s1);
    printf("%s",s2);

    return 0;
}

In this code snippet, the char array C2 doesn't return any error but the char array C1 returns string too long. I know that C1 must require a size of 6 to store 5 characters as it stores the \0 (NULL char) in the last index. But I'm confused why C2 works just fine then?

Also, when C2 is printed using %s, the output is abcde@ where @ is a gibberish character. %s with printf prints all the characters starting from the given address till \0 is encountered. I don't understand why is it printing that extra character at the end?

6
  • I just answered to this question here (though the OP of that question required an explanation from a different angle). No need to post a duplicate answer (espacially because you already have a good answer). Commented Oct 4, 2020 at 16:10
  • No, the c1 must not produce an error. The problem most likely is that you're using a C++, not a C compiler to compile the code Commented Oct 4, 2020 at 17:46
  • In any case, could you be so kind as to add the actual error messages into the question. Commented Oct 4, 2020 at 18:55
  • @AnttiHaapala: Re “No, the c1 must not produce an error”: The C standard permits implementations to provide additional diagnostic messages, although it should be a warning, not an error, as the program should be accepted. Commented Oct 4, 2020 at 18:56
  • @EricPostpischil it is true. However, I personally do not know any C compiler that would produce this message. Commented Oct 4, 2020 at 18:58

2 Answers 2

3

You've created two unterminated strings. Make your arrays big enough to hold the null terminator and you'll avoid this undefined behaviour:

char c1[6] = "abcde";
char c2[6] = {'a','b','c','d','e','\0'};

Strictly, speaking the latter doesn't actually require the '\0'. This declaration is equivalent and will include the null terminator:

char c2[6] = {'a','b','c','d','e'};

I personally prefer the first form, but with the added convenience of being able to leave out the explicit length:

char c1[] = "abcde";
Sign up to request clarification or add additional context in comments.

3 Comments

Would char a[100]={'x'}; be initialized with 99 null characters?
Yes - any array members not explicitly initialized get 0. C11 6.7.9.
Gnarly! You do indeed learn something new every day.
2

I know that C1 must require a size of 6 to store 5 characters as it stores the \0 (NULL char) in the last index. But I'm confused why C2 works just fine then?

The compiler does not complain about the initialization of c2 because initializing with {'a','b','c','d','e'} does not implicitly include a terminating null character.

In contrast, initializing with "abcde" does include a null character: The C standard defines a string literal to include a terminating null character, so char c1[5]="abcde"; nominally initializes a 5-element array with 6 values. The C standard does not require a warning or error in this case because C 2018 6.7.9 14 indicates that null character may be neglected if the array does not have room for it. However, the compiler you are using1 has chosen to issue a warning message because this form of initialization often indicates an error: The programmer attempted to initialize an array with a string, but there is not room for the full string.

In C, arrays of characters and strings are different things: An array is a sequence of values, and an array of characters can contain any arbitrary values of those characters, including no zero value at the end and possible zero values in the middle. For example, if we have a buffer of bytes from a binary file, the bytes are just integer values to us; their meaning as characters that might be printed is irrelevant. A string is a sequence of characters that is terminated by a null character. It cannot have internal zero values because the first null character marks the end.

So, when you define an array of characters such as char c1[5], the compiler does not automatically know whether you intend to use it to hold strings or you intended to use it as an array of arbitrary values. When you initialize the array with a string, your compiler is essentially figuring you intend to use the array to hold strings, and it warns you if the string you use to initialize the array does not fit. When you initialize the array with a list of values, your compiler essentially figures you may be using it to hold arbitrary values, and it does not warn you that there could be a missing terminator.

Also, when C2 is printed using %s, the output is abcde@ where @ is a gibberish character.

Because c2 does not have a terminating character, attempting to print it runs off the end of the array, resulting in behavior not defined by the C standard. Commonly, printf continues reading memory beyond the array, printing whatever happens to be there until it reaches a null character.

Footnote

1 This assumes you are indeed using a C compiler to compile this source code. C++ has different rules and does not permit an array being initialized with a string literal to be too short to include the terminating null character.

6 Comments

I believe OP is using a C++ compiler... Unfortunately OP did not include the error messages in the question.
@AnttiHaapala: MSVC warns even in its C mode.
Hmm, must be an option then, doesn't warn on Compiler Explorer
Ah true, if you add /Wall or similar
@AnttiHaapala Yeah I'm using C++ compiler. The error was initializer-string for array of chars is too long. I uploaded it but it was cut out in the edit.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.