0

I participated Google Code Jam 2019 Round 1C yesterday. Below was the part of the code.

char str[5]={r1,r2,r3,r4,r5};
printf("%s\n", str);

The judge gave Wrong Answer. But if I add the line str[5]='\0'; before print statement, It works.

Actually I checked running the program and it seems to be printing normally. Then, may I know why the judge is giving Wrong Answer and where It could have gone wrong? Can anyone please help by telling me the difference of printing string with null character and without null character? Can someone confirm if it will give always correct result?

Ramesh
  • 392
  • 1
  • 12
  • 39
  • 2
    An array of characters is not even a string unless it is NULL-terminated. The fact that sometimes it gets printed is out of mere luck (a.k.a. undefined behavior). If you want to display five characters, use `write()`. – DYZ May 05 '19 at 03:44
  • 1
    ... or specify an appropriate precision in the field directive in your format: `printf("%.5s\n", str);`. Or make the array one element longer, so that it can genuinely accommodate a terminator at the end. – John Bollinger May 05 '19 at 03:54
  • But any way around, we can't tell you for certain the actual reason the judge failed your submission. You have more information about that than we do. – John Bollinger May 05 '19 at 03:56
  • 1
    @JohnBollinger What (if anything) specifies that you can safely pass an unterminated string to `printf` if the field width will cut it off? I don't think that's permissible. –  May 05 '19 at 04:18
  • 2
    @duskwuff: C standard says for `fprintf`: "Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more than that many bytes are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character." So if the precision is specified it is implied that null character is not required. – Yakov Galka May 05 '19 at 04:29
  • [C11 7.1.1p1](http://port70.net/~nsz/c/c11/n1570.html#7.1.1p1) "A string is a contiguous sequence of characters **terminated by and including the first null character**" – Antti Haapala -- Слава Україні May 05 '19 at 04:47
  • I tested multiple times. It always prints correctly. I don't see any incorrect behavior. Can someone confirm otherwise? Because If I get confirmation that it will print always correct without null character, I will take up this issue with Google team and will claim that the program is correct. – Ramesh May 05 '19 at 05:45
  • @ybungalobill That only specifies how many characters will be written. It doesn't specify how much data will be read from the input -- I would be very surprised if the standard prohibited a `printf()` implementation from calling `strlen()` on a string input. –  May 05 '19 at 05:46
  • I tested multiple times. It always prints correctly. I don't see any incorrect behavior. Can someone confirm otherwise? Because If I get confirmation that it will print always correct without null character, I will take up this issue with Google team and will claim that the program is correct. In fact the program gives correct answer with the python testing tool given by Google team for testing purpose. I feel the Judge also is supposed to give correct result verdict but it gave WA. It is very surprising that their own tool contradicts with their Judge. – Ramesh May 05 '19 at 05:51
  • 1
    @duskwuff: if you were right then there would be no point in the condition "If the precision is not specified or is greater than the size of the array". It does seem to be an intended feature, and I challenge you to find an implementation that interprets it otherwise. – Yakov Galka May 05 '19 at 05:54
  • 3
    @duskwuff you're incorrect. ybungalobill is correct. And Ramesh is utterly hopeless. – Antti Haapala -- Слава Україні May 05 '19 at 06:23
  • 1
    @duskwuff, `char` arrays are not required to be null-terminated in general, and the specifications for `printf` nowhere use the term "string", only array. *Only* the provision quoted by ybungalobill places any requirement for a terminator in the array whose elements are printed in conjunction with a `%s` directive. So be surprised. A conforming implementation cannot safely assume that a conforming program provides a null-terminated array if they specify a precision. – John Bollinger May 05 '19 at 12:53
  • @JohnBollinger Do you mean, printing char array with out null using %s will give correct result always? If so, why Code Jam platform judge gives me Wrong Answer though their interactive testing tool accepts my program as correct? Is there anyway to configure compiler not to accept this kind of code? – Ramesh May 06 '19 at 07:53
  • 1
    NO, @Ramesh, absolutely not. I mean that an unterminated `char` array may be printed via `%s` *with a precision parameter appropriate to the data being printed*, as demonstrated for your particular case by my first comment, and expanded upon in ybungalobill's answer. I'm having trouble understanding why you can't accept that your original code is wrong. – John Bollinger May 06 '19 at 11:51

1 Answers1

4

C strings are null-terminated by convention. That means that printf, or any other function receiving a C string, will read the pointed memory till it encounters a null character.

In your case there's no null terminator in str, so printf will keep reading from whatever memory comes next. This is undefined behavior. When you tried it yourself, you were lucky to have null following right after str, so printf stopped right ahead. If you are less lucky you can get garbage or a segfault. That's probably what happened when the code was executed by the judge.

Note that str[5] = '\0' is undefined behavior too, because str[5] is beyond the size of the array.

Alternative solutions that work:

Include the null terminator:

char str[6]={r1,r2,r3,r4,r5,0};

Or pass the size of the buffer to printf:

printf("%.5s\n", str);

Or:

printf("%.*s\n", (int)sizeof(str), str);

Or use fwrite:

fwrite(str, 1, sizeof(str), stdout);
fputc('\n', stdout);
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • 1
    Should be noted that the last example will only work if `str` is an array and not a pointer – Govind Parmar May 05 '19 at 04:27
  • This statement "because str[5] is beyond the size of the array." is wrong. We don't need to go for str[6] to accomodate '\0'. By default, str[5] will take '\0' if we get through scanf. So, always the last index n if we define str[n] is reserved for '\0' as for as I remember. – Ramesh May 05 '19 at 05:41
  • 2
    @Ramesh: no, it is absolutely correct. the size of the array is as big as you declare. You confuse it with `"string-literals"`. If you write `char s[] = "abcde";` then the size of the array will ineed be 6 to include the null terminator. But that's not the case in your code. Instead of arguing just go ahead and check the size of the array with `sizeof(str)`. – Yakov Galka May 05 '19 at 05:49
  • @ybungalobill You mentioned we might get garbage or a segfault. But I ran program multiple times and I never get garbage or a segfault. Also, I think printing char array with out null end is correct as I am not able to reproduce something otherwise. – Ramesh May 06 '19 at 08:59
  • 2
    @Ramesh: your question was "why the judge rejected your answer" and the answer is "because its not standard conforming". The point of writing standard conforming code is to guarantee that the code works the same on all implementations. What happens on your specific computer is irrelevant, as on another standard conforming implementation it may give different results. I bet that Google Code Jam uses some extra checks internally for judging purposes. – Yakov Galka May 06 '19 at 17:09