C variable initialization and execution [duplicate] - c

This question already has answers here:
Is un-initialized integer always default to 0 in c?
(4 answers)
Closed 1 year ago.
In C, we know that without initializing a variable, it holds a garbage value. Yet in online compilers and also, in an IDE, when I tried this program it got compiled and there was a perfect output. When I tried to print the same without the while loop, it returned a garbage value. So, is not initializing fine?
#include <stdio.h>
int main() {
int j;
while(j<=10){
printf("\n %d",j);
j=j+1;
}
}

Try disassembling your code, for example "gcc -S test.c", so you can see that there is no instruction dedicated to initializing the integer "j" with or without loop. Greetings.

… it holds a garbage value.
When anybody says an object has a garbage value, they are being imprecise with language.
There is no value that is a garbage value. For 32-bit two’s complement integers, there are the values −2,147,483,648 to +2,147,483,647. Each of them is a valid value. None of them is a garbage value.
What it actually means to say something has a garbage value, if the speaker understands C semantics, is that the value of the object is uncontrolled. It has not been set to any specific value, and therefore whatever value you get from using it is a happenstance of circumstances. It may be some value that was in the memory of the object before it was reserved to be the memory for that object.
However, it might be other things. When an object is uninitialized, the C standard not only has no requirement that the memory of the object have any particular value, it has no requirement that the object behave as if it had any fixed value at all. This frees the compiler for purposes that are useful for optimization in other situations. But it means that, if you have int x; printf("%d\n", x); int y = x+3; printf("%d\n", y);, the compiler does not have to load x from memory each time it is used. Because x is uninitialized, the compiler is not required to do any work to load it from memory. For the printf("%d\n", x);, the compiler might let x be whatever value is in the register that would be used to pass the second argument to printf. For the int y = x+3;, the compiler might let x be whatever is in some other register that it would use to hold the value of x if x were defined. This could be a different register. So printf("%d\n", x); might print “47” while int y = x+3; printf("%d\n", y); prints “−372”, not “50”.
Sometimes an uninitialized object might behave as if it started with the value zero. This is not uncommon in short programs such as the one in the question, where nothing has used the stack much yet, so the part of it reserved for j is still in the initial state the program loader put it in, filled with zeros. But that is happenstance. When you change the program, the compiler might use a different part of the stack for j, and that part might not have zeros in it, because it was used by some of the initial program start-up code that runs before main starts.

Always avoid use a uninitialized variables, because it cause undefined behavior.
Uninitialized variables
Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is assigned a memory location by the compiler, the default value of that variable is whatever (garbage) value happens to already be in that memory location! A variable that has not been given a known value (usually through initialization or assignment) is called an uninitialized variable.
For your reference:
https://wiki.sei.cmu.edu/confluence/display/c/EXP33-C.+Do+not+read+uninitialized+memory
https://www.learncpp.com/cpp-tutorial/uninitialized-variables-and-undefined-behavior/

Related

Does scanf() update constant variables?

It seems that scanf() updates constant variables.
As far as I know, constant variables are supposed to have fixed values.
In the following code...
#include <stdio.h>
int main () {
const int testInteger = 0;
printf("Before 'scanf', the value of the variable 'testInteger' is %d.\n", testInteger);
// Does 'scanf' update constant variables?
printf("Enter an integer: ");
scanf("%d", &testInteger);
printf("After 'scanf', the value of the variable 'testInteger' is %d.\n", testInteger);
return 0;
}
...by entering the value of '50', it gives the following output:
Before 'scanf', the value of the variable 'testInteger' is 0.
Enter an integer: 50
After 'scanf', the value of the variable 'testInteger' is 50.
I would like to know why does scanf() update the value of the 'testInteger' constant variable.
Yes, it's supposed to have constant value, but it doesn't magically guarantee it.
You took an address of this variable (of type const int *) which is nothing more than a number pointing to some memory. Then, by passing it to scanf, you violated the contract off const-ness (didn't you get any warnings? Do you compile with -Wall?): it was used as a regular int* pointer.
C relies on the hardware to enforce the read-only-ness of const variables. Most computer hardware can only enforce read-only-ness of large blocks of memory (known as "pages"), not individual int-sized variables.
You declared testInteger as a const int, but because it is otherwise an ordinary local variable -- it has "automatic storage duration", in the language of the C standard -- storage for it is allocated in a location (known as "the stack") whose large blocks have to remain writable for normal operation of the program, so the hardware cannot enforce its constness.
If you change the declaration of testInteger to static const int testInteger, or if you declare it as a global, then it will be allocated in a special region of memory reserved for const variables (the "read-only data segment") whose blocks of memory are unwritable, and your program will crash inside the guts of scanf when it tries to write to testInteger.
It is almost always the Right Thing to declare const data objects as globals / with static storage duration anyway, so this hardware limitation is not a big deal in practice. (Well, actually, it is a big deal, but for completely unrelated reasons.)
Attempting to write a const object is undefined behavior (UB). Might work, might not, might crash, might ...
const int testInteger = 0;
scanf("%d", &testInteger); // UB
There are a couple of issues here.
First, const only means "this thing may not be the target of an assignment operator", not "this thing must be stored in read-only memory." The compiler is only required to issue a diagnostic if a const-qualified variable is the target of an assignment operator.
Secondly, the %d conversion specifier for scanf expects an argument of type int *, but we're passing an argument of type const int *. However, this isn't a constraint violation the way assignment is, so no diagnostic is required. Since we're passing the wrong type of argument to scanf for that conversion specifier, the behavior is undefined, which means that neither the compiler nor the run-time environment are required to handle the situation in any particular way. In this case, your implementation updated the variable. In an implementation where testInteger was stored in read-only memory, you might get a segfault or other runtime error, or the variable may simply not be updated.
VC doesn't warn you, you have to add -Wall, I'm using either Dev C or Geany. It's not a compiler error though, it's just a not desirable output.
I believe there are OS'es and compilers that can store const variables into read-only memory, but I also believe that most situations don't do that. It's more of a way to let a compiler know "I want you to warn me if I try to change this variable by mistake", but the compiler doesn't go so far as to check pointers to it, only direct references.

Peculiarity in functions of "C" Language [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 2 years ago.
Since i am new to C Language i was learning it from tutorials point when i encountered a peculiarity in functions which got my head banging while understanding it.
I have learnt that if variables are defined inside a function then there scope is local to that function and whenever the control transfers from function the variables are no more available and cleaned.
But its not in the case i have created, the program below is still printing the value of variable p which is defined in the test function so when control from test function is transferred why i am still able to get its value? its still printing the value of variable p that is 80 in screen why?
#include <stdio.h>
int *test();
int main()
{
int *ab
ab = test();
printf("%d\n",*ab);
return 0;
}
int *test()
{
int p = 80;
return (&p);
}
Help me understand this peculiarity Please.
What you are experiencing is a symptom of undefined behavior.
A variable's address is no longer valid after its lifetime ends. When you attempt to dereference that address, you may see the value you had before, or you may see something else.
Try duplicating the printf call in main and you'll likely see a different value.
What is most likely happening is that before the first call to printf the area of memory that contained p hadn't yet been overwritten. Then when printf is actually called, the stack frame for that function is using the same memory that the stack frame for test was using and the memory previously used by p is now overwritten. So when you dereferences ab in main after calling printf you'll see whatever value that function placed there.
Accessing an out-of-scope variable is Undefined Behaviour , and hence, by definition, results can vary infinitely and unpredictably, as variables change (compiler flags, OS, etc.)
Your variable does go out of scope but this only means it is no longer 'reserved'. However, unlike newer languages where this may raise compile-time errors, in C this is merely a warning, which may appear if you specifically ask the compiler to give you extra warnings.
So the code will compile.
Here, the variable goes out of scope, but, assumably, no further usage of memory occurs , and so the value at the address of test stays same . If more variables were declared/initialised/used , then likely that address would have been overwritten with another value, and you would have printed something unexpected - to be real, even this result was unexpected, hence your question !
The thing to remember is - variables in C are like chairs in a hall(which is akin to memory). The chair's position, the number of chairs is all static/fixed. What can be changed is who sits at what chair.
So, if you ask a friend to sit at a convenient chair and 5 minutes later tell him he is no longer required , whether he stays there or gets up and someone takes his place is something you cannot predict without looking and reading at an out-of-scope address is similarly undefined , since it cannot be predicted beforehand !
Other analogies may be parking spaces, ship-containers, etc.
The difference is that the address won't be overwritten / 'deleted' until something else comes up which needs to be stored (this is also how Disks manage 'deletion' which is actually nothing but un-reserving hardware locations) .
And when you think about it, it makes a lot of sense from the efficiency standpoint - you no longer have to waste time doing a useless 'overwrite with 0' or whatever and instead only write when you have a real value to store to memory !
( 1 operation instead of 2, half the work.)
Even though the variable shouldn't be "existing" anymore, the computer is a little bit lazy, and it won't delete the value at an address.
That is how you can manipulate the memory, if you try to see memory that doesn't belong to your program, you'll be able to see some weird values, because they stay in the memory even though they aren't used anymore.
Here is an example that may illustrate the UB you're looking at:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int *test();
void run_random();
int main()
{
srand(time(NULL));
int *ab;
int i=0, N = 5;
for (i=0; i<N; ++i){
ab = test();
run_random();
printf("%d\n",*ab);
}
return 0;
}
int *test()
{
int p = 80;
return (&p);
}
void run_random()
{
int i=0, N=1000;
for (i=0; i<N; ++i){
int rvar = rand();
}
}
In your code, the variable from test() happens to still have the expected value on the stack memory. This is what I see when re-running the function in a loop - *ab is still equal to 80, you can see it too if you comment out the run_random() call.
But when I add the second call, the call to run_random() - I start getting ab equal to N in the run_random() i.e. 1000, as that memory location is now populated with a different variable's value (it was free to use by the OS to begin with, as soon as test() stopped executing).
In your case you may end up seeing something else, of course, perhaps even still the expected value. That is the point of UB, you don't really know what will pop-up.

No garbage value or error shown while running this C program

In C, inside a function, if we declare a variable and don't initialise it, it generates a garbage value and stores it in the variable.
Whereas in Java, it does not allow you to use a local variable without initialising in a method.
But the code below, when compiled and ran on online C compilers,
Idk why instead of generating garbage values, it is printing "123". (without quotes)
#include <stdio.h>
void f();
int main(){
f();
f();
f();
}
void f(){
int i;
++i;
printf("%d", i);
}
"I do not know why instead of generating garbage values, it is printing "123"."
When any expression in the program invokes Undefined Behavior, which is made by
incrementing and printing the indeterminate value of i, the result/output does not need to be wrong, but there will never be a guarantee that it will be correct, which is a reason to never rely on any of such a code, does not matter if it prints the right values in one specific case.
Thus, you do not need to smash your head around finding a reason for that behavior.
Because of common implementations of C, an uninitialized value near the start of a C program is likely to be 0, so your subsequent ++i operations change it to 1 2 and 3.
However, take good note of this:
Just because it is likely to be zero does not guarantee it will be zero.
This is undefined behavior, and the values could correctly come out to be anything.

How garbage values are assigned to variables in c

C code :
int a;
printf("\n\t %d",a); // It'll print some garbage value;
So how does these garbage values are assigned to uninitialized variables behind the curtains in C?
Does it mean C first allocates memory to variable 'a' and then what ever there is at that memory location becomes value of 'a'? or something else?
Does it mean C first allocates memory to variable 'a' and then what ever there is at that memory location becomes value of 'a'?
Exactly!
Basically, C doesn't do anything you don't tell it to. That's both its strength and its weakness.
Does it mean C first allocates memory to variable 'a' and then what
ever there is at that memory location becomes value of 'a'? or
something else?
Correct. It is worth mentioning that the "allocation" of automatic variables such as int a is virtually nonexistent, since those variables are stored on the stack or in a CPU register. For variables stored on the stack, "allocation" is performed when the function is called, and boils down to an instruction that moves the stack pointer by a fixed offset calculated at compile time (the combined storage of all local variables used by the function, rounded to proper alignment).
The initial value of variables assigned to CPU registers is the previous contents of the register. Because of this difference (register vs. memory) it sometimes happens that programs that worked correctly when compiled without optimization start breaking when compiled with optimization turned on. The uninitialized variables, previously pointing to the location that happened to be zero-initialized, now contain values from previous uses of the same register.
Initially memory is having some values, those are unknown values, also called garbage values,
when ever we declare a variable some memory was reserved for the variable according to datatype we specified while declaring, so the memory initial value is unknown value, if we initialize some other value then our value will be in that memory location.
int a;
While declaring a variable, the memory is allocated. But this variable is not assigned which means the variable a is not initialized. If this variable a is only declared but no longer used in the program is called garbage value.
For example:
int a, b;
b=10;
printf("%d",b);
return 0;
Here it's only declared but no longer assigned or initialized. So this is called garbage value.
Does it mean C first allocates memory to variable 'a' and then what ever there is at that memory location becomes value of 'a'?
No, it does not mean that.
When an object is not initialized, the C standard does not provide any plan for how its value is determined. Not only that, the program is not required to behave as if the object has any fixed value. It can vary as if the memory reserved for it were not held in any fixed state, just fluctuating.
Here are the specific C 2018 rules about that:
The so-called “value” of an uninitialized object is indeterminate, per 6.2.4 6 for objects with automatic storage duration without variable length array type, 6.2.4 7 for those with variable length array type, 7.22.3.4 2 for objects allocated with malloc, 7.22.3.5 2 for additional space allocated by realloc, and 7.22.3.1 2 for aligned_alloc. Other objects, such as those with static storage duration, are initialized.
Per 3.19.2, an indeterminate value is “either an unspecified value or a trap representation”.
Per 3.19.3, an unspecified value is a “valid value of the relevant type where this document imposes no requirements on which value is chosen in any instance”.
This means that in each instance an object is used, the C standard does not impose any requirements on which value is used for it. It is not required to be the same as a previous use. The program may behave as if it does not hold any fixed value. When it is used multiple times, the program may act as if it has a different value each time. For example, the C standard would allow printf("%d %d %d\n", a, a, a); to print “34 -10200773 2147483204”.
A way this can happen is that, while attempting to compile the code int a; printf("%d %d %d\n", a, a, a);, the compiler has nowhere to get a from, because it has never been given any fixed value. So, instead of generating useless instructions to move data from uninitialized memory to where the arguments are passed, the compiler generates nothing. Then printf gets called, and the registers or stack locations where the arguments are passed contain whatever data they had from earlier. And that may well be three different values, which printf prints. So it looks to an observer of the output as if a had three different values in printf("%d %d %d\n", a, a, a);.
(In addition, using the value of an uninitialized object with automatic storage duration that has not had its address taken is explicitly undefined behavior, because 6.3.2.1 2, about converting an object to its value, says “If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.” So, when there is an object meeting these criteria, using its value can break the program completely; it might not only have different values at different times, but the program might abort, go down a branch different from what you expected, not call printf when there is a printf in the source code, and so on.)
Which I have investigated years back is this:
The answer is that garbage value is the leftover of previous program.
So, when you run any program, that uses variables to store values and when it ends OS only release the memory and make it available for other programs but OS does not flush the data in those locations automatically.
So, when you declare a uninitialized variable OS assigns any available memory to that variable, and because you have not assigned any value, the leftover value on that location is not over written and becomes the GARBAGE VALUE for that variable because it is not relevant.
And this can also be proven with a small program by accessing the location of variable in previous program using pointers.

Why does gcc give me this result?

When I run this code gcc gives me the output 10.
Can someone explain to me why it gives me 10? :)
#include <stdio.h>
int f(int x) {
int y;
y = 2*x;
}
int g() {
int z;
return z;
}
int main() {
int x=5;
f(x);
printf("%d\n",g());
}
this is undefined behavior - you are referencing a variable which has no value set to it. likely, it gives 10 because the compiler has used the same memory location for the variable in f(), but there is no guarantee of that, it should not be depended on, and is nothing more than a curiosity.
There's nothing to explain. Your code exhibits undefined behaviour on two separate, unrelated occasions: First f isn't returning anything despite being declared as returning int, and second because g returns an uninitialized value.
Practically, the way the functions will be put on the call stack will have caused the local y (which eventually has the value 10) to be in the same place as the return value of g() in the printf call, so you happen to see the value 10. But that's more or less a matter of luck.
Here:
int g() {
int z;
return z;
}
This reads:
int g():
reserve memory for an integer, call it z.
return whatever is in that reserved memory.
You never used that reserved memory for your integer. Its value is whatever was at that address before you chose to use it (or not use it, rather). That value could be anything.
You do the same in your other function. What you are doing is reading uninitialized memory. You can google that up for further information. See also the "stack" and the "heap", dynamic memory, and other related topics.
g returns an unitialized varable from the stack, in your example that location was last set by the F function giving you your answer of x*2 = 10
Because you're not initializing z, and it's using the same location on the stack as y. Since you're not initializing it the old value is still there.
This is a perfect example of why people fear optimizations and when they brag about finding compiler bugs to their bosses. This code as others have alluded to will throw warnings about using uninitialized variables in g(). With your compiler settings, it is using the old value on the stack from the call to f(5). With different compiler optimization settings, it will likely have effects on how variables end up on the stack and you'll end up getting a different results when you make changes which appear unrelated. This is undefined behavior and there is no guarantees on what value will result however it is usually easy to explain by understanding the call order and how the compiler sets up the stack. If there are warnings when you're troubleshooting weird behavior like this, fix the warnings first then start asking questions about why.

Resources