-5

I tried these lines of code and found out shocking output. I am expecting some reason related to initialisation either in general or in for loop.

1.)

int i = 0;
    for(i++; i++; i++){
        if(i>10)    break;
    }
    printf("%d",i);

Output - 12

2.)

int i;
    for(i++; i++; i++){
        if(i>10)    break;
    }
    printf("%d",i);

Output - 1

I expected the statements "int i = 0" and "int i" to be the same.What is the difference between them?

Galik
  • 42,526
  • 3
  • 76
  • 100
  • 7
    the second code can output anything, because `i` is unitialized – fas Sep 28 '19 at 10:41
  • 2
    The "difference between them" is exactly what your code shows: one is initialized to a determinate value, the other is not.The latter full code invokes undefined behavior as a result. – WhozCraig Sep 28 '19 at 10:41
  • 3
    Now you have to remember that C and C++ are two very different language with very different semantics. The code you present is one case where that difference really matters. In one language it's *undefined behavior* immediately. – Some programmer dude Sep 28 '19 at 10:43
  • `static int i;` initializes `i` to zero (*edit*) in C; probably also in C++, but don't take my word for it. – pmg Sep 28 '19 at 10:43
  • @Someprogrammerdude - the difference between C and C++ is not relevant to these two code snippets. The output from the first sample is as described in both C and C++. The second has undefined behaviour in both C and C++. – Peter Sep 28 '19 at 11:08
  • @Peter In C++ just *using* an uninitialized variable is UB. In C it's only UB if it contains a trap value. And integers never have trap values. – Some programmer dude Sep 28 '19 at 11:25
  • 1
    @Someprogrammerdude -- integers **can** have a trap value. The last paragraph of 6.2.6.2/3 in the C11 standard says that with sign-magnitude and twos-complement representations, a sign bit of 1 and all 0s for the value bits can be a trap representation, and with ones-complement, a sign bit of 1 and all 1s for the value bits can be a trap representation. It's implementation-defined whether such a value is a normal value or a trap representation. – Pete Becker Sep 28 '19 at 12:55

2 Answers2

5

I expected the statements "int i = 0" and "int i" to be the same.

No, that was a wrong expectation on your part. If a variable is declared outside of a function (as a "global" variable), or if it is declared with the static keyword, it's guaranteed to be initialized to 0 even if you don't write = 0. But variables defined inside functions (ordinary "local" variables without static) do not have this guaranteed initialization. If you don't explicitly initialize them, they start out containing indeterminate values.

(Note, though, that in this context "indeterminate" does not mean "random". If you write a program that uses or prints an uninitialized variable, often you'll find that it starts out containing the same value every time you run your program. By chance, it might even be 0. On most machines, what happens is that the variable takes on whatever value was left "on the stack" by the previous function that was called.)

See also these related questions:

Non-static variable initialization
Static variable initialization?

See also section 4.2 and section 4.3 in these class notes.

See also question 1.30 in the C FAQ list.


Addendum: Based on your comments, it sounds like when you fail to initialize i, the indeterminate value it happens to start out with is 0, so your question is now:

"Given the program

#include <stdio.h>
int main()
{
    int i;                   // note uninitialized
    printf("%d\n", i);       // prints 0
    for(i++; i++; i++){
        if(i>10)    break;
    }
    printf("%d\n", i);       // prints 1
}

what possible sequence of operations could the compiler be emitting that would cause it to compute a final value of 1?"

This can be a difficult question to answer. Several people have tried to answer it, in this question's other answer and in the comments, but for some reason you haven't accepted that answer.

That answer again is, "An uninitialized local variable leads to undefined behavior. Undefined behavior means anything can happen."

The important thing about this answer is that it says that "anything can happen", and "anything" means absolutely anything. It absolutely does not have to make sense.

The second question, as I have phrased it, does not really even make sense, because it contains an inherent contradiction, because it asks, "what possible sequence of operations could the compiler be emitting", but since the program contains Undefined behavior, the compiler isn't even obliged to emit a sensible sequence of operations at all.

If you really want to know what sequence of operations your compiler is emitting, you'll have to ask it. Under Unix/Linux, compile with the -S flag. Under other compilers, I don't know how to view the assembly-language output. But please don't expect the output to make any sense, and please don't ask me to explain it to you (because I already know it won't make any sense).

Because the compiler is allowed to do anything, it might be emitting code as if your program had been written, for example, as

#include <stdio.h>
int main()
{
    int i;                   // note uninitialized
    printf("%d\n", i);       // prints 0
    i++;
    printf("%d\n", i);       // prints 1
}

"But that doesn't make any sense!", you say. "How could the compiler turn "for(i++; i++; i++) ..." into just "i++"? And the answer -- you've heard it, but maybe you still didn't quite believe it -- is that when a program contains undefined behavior, the compiler is allowed to do anything.

Steve Summit
  • 29,350
  • 5
  • 43
  • 68
  • It prints 0 even when it is not initialised and even then the result is 1 for the 2nd case. I want to know the reason behind that. – Kavish Madaan Sep 29 '19 at 07:37
  • @KavishMadaan I don't know what you mean by "It prints 0 even when it is not initialised" -- I thought you said it printed 1. But anyway, if by chance `i` starts out containing `-1`, the program will print `1`. – Steve Summit Sep 29 '19 at 11:36
  • @KavishMadaan I'm now a little confused about what you're asking. I thought the question was "Why are the two programs different?", and I hope we've answered that. If you're now asking "How could the first program print 1?", the answer is "If `i` started out as being `-1`". Or are you wondering how an initial value of -1 can cause it to print 1? – Steve Summit Sep 29 '19 at 11:40
  • If I put print statement before the for loop as "printf("%d ",i)" then the output for case 1 is - "0 12" and case 2 is - "0 1" – Kavish Madaan Sep 29 '19 at 13:48
  • There are two possibilities. I will address them in two separate comments. But before that, I have to say: We are probably not going to get to the bottom of this, we are probably not going to find an answer that satisfies you. – Steve Summit Sep 29 '19 at 13:58
  • Possibility one: There's something else going on, that I can't see. I can't see the actual program you're running. I can see two code fragments from yesterday, and I can see your description that "If I put print statement before the for loop ... then the output for ... case 2 is - 0 1". But, to be honest, I don't 100% believe you, without seeing a complete, verbatim copy of the program you're running today. – Steve Summit Sep 29 '19 at 14:02
  • Possibility 2: You are using a modern, optimizing compiler, and it is taking full advantage of the liberty afforded to it when your code contains undefined behavior. As the other answer to your question and several of the comments explain, once your program contains undefined behavior, it can do *anything*, and it doesn't have to make any sense. – Steve Summit Sep 29 '19 at 14:04
  • And see the addendum I added to the answer. – Steve Summit Sep 29 '19 at 14:30
1

The difference is what you already observed. The first code initializes i the other does not. Using an unitialized value is undefined behaviour (UB) in c++. The compiler assumes UB does not happen in a correct program, and hence is allowed to emit code that does whatever. Simpler example is:

int i;
i++;

Compiler knows that i++ cannot happen in a correct program, and the compiler does not bother to emit correct output for wrong input, hece when you run this code anything could happen.

For further reading see here: https://en.cppreference.com/w/cpp/language/ub

The is a rule of thumb that (among other things) helps to avoid uninitialized variables. It is called Almost-Always-Auto, and it suggests to use auto almost always. If you write

auto i = 0;

You cannot forget to initialize i, because auto requires an initialzer to be able to deduce the type.

PS: C and C++ are two different languages with different rules. Your second code is UB in C++, but I cannot answer your question for C.

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126
  • In both C and C++, the int variable is initialised as 0 in my case. I checked that too by printing the value after declaring the variable(it prints 0). My question is why are there 2 different output for same values of i. – Kavish Madaan Sep 29 '19 at 07:46
  • @KavishMadaan `printf("%d",i);` can print anything when `i` is not initialized, `0` is just one out of many possible outcomes you could observe – 463035818_is_not_a_number Sep 29 '19 at 17:54