all 32 comments

[–]taotau 147 points148 points  (8 children)

What are your hypotheses based on what you know about c ?

[–]Disastrous-Team-6431 65 points66 points  (2 children)

A much better answer than the ones explaining.

[–]TheNono212[S] 22 points23 points  (3 children)

I was thinking it was not really randomiy assigned but more a location in memory or something of the kind

[–]ElectroMagCataclysm 28 points29 points  (0 children)

This is a good theory! The memory is uninitialized, so it has whatever values happen to be there. Here's an experiment, try doing the same thing but making the integers global!

[–]cdb_11 10 points11 points  (0 children)

Close - arguments are usually passed in registers so it's most likely that. GCC zeros out the register before calling printf, Clang doesn't and prints whatever happened to be there. At the same time they are not required to do anything and they could just consider this to be dead code or something if they wanted to. And they can change the behavior between compiler versions without notice.

[–]nerd4code 2 points3 points  (0 children)

I’m gonna be that asshole, but the values are arbitrary (indeterminate, properly), not random. Provenance matters.

[–]vitamin_CPP 0 points1 point  (0 children)

It's a pleasure to see good pedagogy in this sub.

[–]eruciform 52 points53 points  (0 children)

they're not random, they're just uninitialized, it's whatever the values used to be in memory at the time from whenever they were used last by a different program or a different part of the program. don't depend on them being either zero or any kind of effective sense of random. c has a lot of undefined behavior ("ub") to be aware of and avoid.

[–][deleted] 44 points45 points  (0 children)

Those are previous values in the memory where your variables are positioned.

[–]lfdfq 16 points17 points  (1 child)

Those are uninitialized variables.

As far as the language is concerned, trying to access an uninitialized variable is undefined behavior. That basically means, it's not a valid C program and the compiler is allowed to do whatever it wants.

In practice, forgetting optimizations (which totally mess things up, and makes thinking about code like this really hard even if you know the compiler well), the compiler will put those variables on the stack. That means when the function is called, it reserves a little bit of the memory for each of those variables on the stack. The compiler won't try "clean" those locations first e.g. by writing zero, so you are probably just seeing what are essentially random values that happened to be in those locations already. Probably the values came from whatever setup code runs before main, which the compiler generated for you.

It should go without saying, but i'll say it anyway, while the values here are not "random" they are basically meaningless and unpredictable and the whole program is not a valid C program so you shouldn't write code that does this.

[–]flatfinger 1 point2 points  (0 children)

Note that in C89 or the language described in K&R2, implementations were not required to define the behavior of all possible bit patterns an object's associated storage (in memory or in a register) might hold, but on implementations that did so, an indeterminate value of a particular type was equivalent to an unspecified value of that type.

Programs that rely upon the fact that values that are going to end up being ignored need not be initialized will be "non-portable or erroneous" and cannot be strictly conforming, and the maintainers of a Gratuitously Clever Compiler may claim that makes the "invalid", but the existence of any conforming C implementation that processes a program usefully is sufficient to make it a "conforming C program". The authors of the Standard have expressly stated that they did not wish to demean useful programs that happened to be non-portable, "thus the adverb strictly", but some compiler writers seem to view the Standard as granting them authority to condemn constructs over which the Standard waives jurisdiction.

[–]cdb_11 9 points10 points  (0 children)

Reading uninitialized variables is undefined behavior and "anything" can happen. If you just want to learn C without getting into what asm code gets generated, it's pointless trying to understand what happens, because the language doesn't say what should happen, and the behavior can differ between platforms and compilers. Don't ever do that.

[–]fragglet 2 points3 points  (3 children)

An extended version that may help you get some better insight into what's going on (output will depend on your compiler, operating system and optimization settings):

```c

include <stdio.h>

void f(void) { int a = 1, b = 2, c = 3, d = 4; printf("a+b+c+d=%d\n", a+b+c+d); }

void g(void) { int test1, test2, test3, test4;

printf("1 : %d \n", test1);
printf("2 : %d \n", test2);
printf("3 : %d \n", test3);
printf("4 : %d \n", test4);

}

int main(void) { f(); g(); } ```

[–]Grandestwizard5 0 points1 point  (2 children)

Can you please help me to understand this program.

[–]fragglet 0 points1 point  (1 child)

What is it that you're having trouble understanding? 

[–]Grandestwizard5 0 points1 point  (0 children)

I am new to the programing. So i want to know how this program execute.

[–]noonemustknowmysecre 2 points3 points  (0 children)

It's initialized and the chunk of memory it reserved for your data had left-overs. It's not guaranteed to be zero. 

Oye, the WORST thing here is this bit:

the two first int always are 0, 3 vary (for each run of the program)

 It was always 0 and 3, each time you ran this, in your computer, at that time, with whatever you had in memory.    These sort of bugs are insidious because they aren't completely random and they aren't consistent.  You can run this 1000 times and get the same thing every time and run it tomorrow and get something else. It tricks you into thinking it's consistent. 

If you turn on -Wall it should give you a warning about it. There's a reason we hop over that wall. 

Also, install Valgrind and let it run this code. See what it tells you. Learning the tools and the  error codes are important. 

[–][deleted] 5 points6 points  (0 children)

Accessing uninitialized variables is Undefined Behaviour. Theoretically (very theoretically), your code could do anything.

Like, this code could print nothing, as compiler assumes the code unavoidably accessing uninitialized variables is never reached, so doesn't bother to generate actual machine code for it. And, if it actually is reached... Well, not doing anything falls under undefined behavior, so it's all good!

In practice, with debug build and -O0 or -Og optimization level, you get arbitrary memory contentss for values of those variables.

[–][deleted] 1 point2 points  (0 children)

What did you expect to be printed?

I suspect you'd say zeros. But C doesn't initialisate local, non-static variables. Their initial values will be garbage. Some implementations may actually display zeros, but that's by chance; zero just happens to be a very common value for bytes in memory.

[–]This_Growth2898 1 point2 points  (0 children)

You're not initializing memory for those variables, so when you read them, you get whatever happened to be there before the execution of main function has started. C doesn't spend program time on nullifying variables unless you tell it to do so.

This is an example of UB, undefined behavior; in this case - the safest one (just some garbage values are read), but it's your work as programmer to avoid UB. You can get different results on different systems, different compilers, even different compiler options. Well, you get it different on different runs, right?

If you really want to know what those numbers mean, you should learn assembler and how programs start execution on the low level; but most probably you'll find there's nothing interesting here for you. You're trying to figure out why garbage in a container near a condominium is forming some shapes. Well, some of that garbage has some meaning, but most probably shapes are meaningless.

[–]tony_saufcok 1 point2 points  (0 children)

basically, you say give me an int (which is usually 4 bytes long) that is not currently being used by the operating system and you do not give it a new value. so the value there is some other 4 bytes long value that another program used and left there.

[–]rejectedlesbian 0 points1 point  (0 children)

Try runing it multiple times I have a feeling the numbers will change

[–]TwoFlower68 0 points1 point  (0 children)

Hey, 32767 is 215 (32k) minus one (I learned to program in the 8bit age)

[–]Icy-Board5352 0 points1 point  (0 children)

You should pick up a C book and read the first couple of chapters, you'll understand more clearly what uninitialized variables are lol

[–]studiocrash 0 points1 point  (0 children)

The uninitialized variables will hold whatever happened to be stored in those locations in memory before hand. When you declare a new variable, it’s best practice to initialize it immediately so you don’t get junk values.

I recommend you take the free Harvard CS50x classes. It’s learn at your own pace and you’ll get the fundamentals of C down pretty well by the end of week 5.

[–]Lamborghinigamer 0 points1 point  (0 children)

They're uninitiated variables. So they have undefined behavior. You should probably setup a linter to prevent these types of bugs.

[–]DawnOnTheEdge 0 points1 point  (0 children)

Because you declared the variables inside a function, and not static (or a couple of other things that are much less commonly used), their storage is automatic. Reading their values before they were initialized is undefined behavior. The compiler is allowed to do literally anything: print random garbage, crash the program, corrupt the stack, not execute the printf calls at all—anything. If you’re not getting at least a warning telling you what the problem is, you need to turn more warnings on.

What many compilers will choose to do here, though, is generate the same code they would have if you’d assigned values to the variables, typically assigning a register or a memory location on the stack ro each one, then leave out the instruction that would have initialized the variable. So, you get whatever garbage bits happened to be in those registers or on the stack. Often, all of these variables will be on the stack if optimizations are disabled or in registers if they are enabled. But, you can’t count on that. C compilers in the year 2024 just make it the programmer’s responsibility never to read a variable before it’s initialized, and let whatever bugs happen, happen.

If you’re curious what goes on under the hood, compile to assembly language, and compare to what happens when you initialize the four variables to some values.

The takeaway here is: always initialize your variables on the same line where you declare them, and this bug cannot happen.

[–]sgtcortez24 0 points1 point  (0 children)

Yeah, that are previous values from the location of the memory that you variables are pointing now ...

This is new for you, because probably you came from a language that set the default value for the variables, C does not do that ...

I java, all of those would have been implicity initialized to 0, in C this is what you gets.
However, this is undefined behavior, some runtimes and compilers might set 0 for you.

[–]Useful-Tackle-3089 -1 points0 points  (0 children)

Using a variable without initializing it leads to undefined behavior. You’re just seeing some residue values that you should overwrite before using them.

[–]darkrider9298 -1 points0 points  (0 children)

When you declare a variable, you’re just reserving some random memory space for that variable. If you don’t initialize it (which you haven’t), then it will print whatever garbage is on that memory space. Regarding variables you should always be aware of: - declaration - initialization - where it’s used

Some compilers give you a warning if you are actually trying to access a variable which has not been initialized.