0

The following code works as expected and outputs ABC:

#include <stdio.h>

void printString (char toPrint [100]);

int main()
{
  char hello [100];
  hello[0] = 'A';
  hello[1] = 'B';
  hello[2] = 'C';
  hello[3] = '\0';

  printString(hello);

}

void printString (char toPrint [100]) 
{
  int i = 0;

  while (toPrint[i] != '\0')
  {
    printf("%c", toPrint[i]);
    ++i;
  }

}

But if I remove the line that adds the null-character

  hallo[3] = '\0';

I get random output like wBCÇL, ╗BCÄL, ┬BCNL etc.

Why is that so? What I expected is the loop in printString() to run forever because it doesn't run into a '\0', but what happend to 'A', 'B' and 'C'? Why do B and C still show up in the output but A is replaced by some random character?

gnidoc
  • 47
  • 7
  • 4
    Probably because it happens to hit the value for '\r', which will reset the cursor to the start of the line I'm guessing. – robthebloke Jan 09 '20 at 05:21
  • Because in the second case, you've a byte array (not a string) that has no null byte where you hope for one. Use `char hello[100] = "";` or equivalent to initialize everything to null bytes. – Jonathan Leffler Jan 09 '20 at 05:21
  • @Jonathan Leffler That does not explain that behaviour in my eyes. Yes, the null byte is (purposely) missing. Then the loop should not end until it finds some null-byte somewhere in the memory by accident. I get that. But why is the initial 'A' replaced by a random character? What has that to do with a missing null-character? – gnidoc Jan 09 '20 at 05:24
  • 3
    Undefined behaviour can do whatever it likes and it doesn’t have to make any sense. As someone else suggested, maybe one of the characters is a carriage return. – Jonathan Leffler Jan 09 '20 at 05:25
  • @robthebloke Sounds reasonable. In that case I would expect an ouput that does not match the pattern xBCxx once I reboot and run the program again, with different memory content surrounding it. I'll try. – gnidoc Jan 09 '20 at 05:28
  • Termination of `printString` is depend on `\0` character. If your remove that then your relying on stack value to terminate the loop – TruthSeeker Jan 09 '20 at 05:36
  • 1
    And indeed: If I run the same code on different machines, I do get "ABC" followed by random characters. Learned a lot from that, thanks! – gnidoc Jan 09 '20 at 05:36
  • When will the loop stop? When a nul-character is read from memory. So what happens if you remove the nul-character at the end of the string? Well, the loop keeps iterating screaming though indeterminate values until it happens to find a `0` byte in memory, and then stops. The goofy characters are just what happened to be between where the end of the string was and where the first nul-byte was found. Just good ole *Undefined Behavior* at its best... – David C. Rankin Jan 09 '20 at 06:30

3 Answers3

1

You declaration of hello leaves it uninitialized and filled with random bytes

int main()
{
 char hello [100];
 ...
}

If you want zero initialized array use

int main()
{
 char hello [100] = {0};
 ...
}
  • As mentioned, I did that on purpose. What I did not understand though is why it never printed 'ABC' and then some random characters AFTER that, which is what I expected. Question was answered above, now everything makes sense. – gnidoc Jan 09 '20 at 05:35
0

There must have been, by pure chance, the value for \r somewhere in the memory cells following those of my array hello. That's why my character 'A' was overwritten.

On other machines, "ABC" was ouput as expected, followed by random characters.

Initializing the array with 0s, purposely omitted here, of course solves the problem.

edit: I let the code print out each character in binary and toPrint[5] was indeed 00001101 which is ASCII for \r (carriage return).

gnidoc
  • 47
  • 7
  • I think you have answered your question quite correctly, at least better than the others. If the limiting `'\0'` is found *after* `hello`, you are invoking undefined behavior, however. Please mark this answer. – the busybee Jan 09 '20 at 07:05
  • The next time you run this, the `\r` might not be where you found it this time. – babon Jan 09 '20 at 08:20
0

When you declare an automatic like char hello [100];, the first thing to understand is that the 100 bytes can contain just about anything. You must assign values to each byte explicitly to do / have something meaningful.

You are terminating you loop when you find the \0 a.k.a the NUL character. Now, if you comment out the instruction which puts the \0 after the character c, your loop runs until you actually find \0.

Your array might contain \0 at some point or it might not. There are chances you might go beyond the 100 bytes still looking for a \0 and invoke undefined behaviour. You also invoke UB when you try to work with an unassigned piece of memory.

babon
  • 3,615
  • 2
  • 20
  • 20