Use of automatic variable outside its scope in C [duplicate] - c

This question already has answers here:
What happens when a variable goes out of scope?
(3 answers)
Closed 6 years ago.
I am studying the working of an automatic variable. I know that it is only accessible inside the block or function in which it is declared and its lifetime is within that same function or block. So the following piece of code I am trying to check.
/Declaration of header files/
void testfn(void);
int *p;
int main(void)
{
testfn();
print("%d\n",*p);
return 0;
}
void testfn(void)
{
int x=444;
p=&x;
}
The output is - 444
I am wondering that when the testfn(); exits,the variable x will be destroyed. Then how in main function the pointer (*p) prints 444.
How this works...or if I am missing something.
Please clarify my doubt.
Thanks

It is coincidence that the original value still remains. With another compiler, or with another compilation configuration, it could take any other value or the program could just crash.
If between the testfn and printf functions you call any other function that does something with its local variables, you might see that the 444 value is not obtained anymore. But this is just, again, coincidence.

p points to the stack where x was stored. If the memory location hasn't been used for something else you will most likely get 444.
Try to insert another function call before printing p and see what happens:
#include <stdio.h>
#include <math.h>
void foo() {
int y=123;
}
void testfn(void);
int *p;
int main(void)
{
testfn();
foo();
printf("%d\n",*p);
return 0;
}
void testfn(void)
{
int x=444;
p=&x;
}
On my machine, the output is now:
123
Since the code results in undefined behaviour, the result could be different if I try this on another platform. But you can see that undefined behaviour can lead to strange bugs.

The memory location that was previously reserved for variable x is not overwritten yet. But it may be at any time. That's why your code leads to undefined behaviour.
In the following example, the memory location that was previously reserved for variable x will be overwritten by the value that is assigned to the variable y. Since the pointer p still points to that location, *p will evaluate to this new value:
#include <stdio.h>
int *p;
void test1(void) {
int x = 444;
p = &x;
}
void test2() {
int y = 15;
}
int main(void) {
test1();
test2();
printf("%d\n",*p);
return 0;
}

The fact that the value still remains is completly coincidental (not guaranteed) because nothing has overwritten it yet.
You can not count on this, it may fail, may print garbage or may crash your program or pc even.
Don't use this, it is considered undefined behavior.

Related

Passing Pointers to Functions in C [duplicate]

This question already has an answer here:
Confusion about the fact that uninitialized pointer points to anywhere
(1 answer)
Closed 4 years ago.
I'm going to take data structures course this year, so I decided to renew my knowledge about C by doing some simple tasks about pointers in C, and I have noticed one thing about passing pointers to functions, that I can't really understand.
Let's say we have a function:
void assignValueTen(int *var){
*var=10;
}
We can call this function from main like this:
int main( void ){
int x;
assignValueTen(&x);
printf("The value of x is %d.\n",x);
return 0;
}
The output of this would be:
The value of x is 10.
We can also call this function like this:
int main( void ){
int x, *y;
y=&x;
assignValueTen(y);
printf("The value of x is %d.\n",x);
return 0;
}
The output of this would also be:
The value of x is 10.
However, the statement below does not work as expected:
int main( void ){
int *x;
assignValueTen(x);
printf("The value of x is %d.\n",*x);
return 0;
}
Output of the code above is:
Process exited after 6.723 seconds with return value 3221225477
So, why does the code compile but not work as expected?
Is it because the pointer is not yet assigned to any address before in the last example?
Can somebody explain why this is happening in a little more detail?
Thanks a lot!
The one that does not work is because x is not assigned any value in particular. The assignment in the function is assigning wherever that uninitialized variable happens to point and that is very unlikely to be a valid address (as the hardware sees things) and even if it is valid (again according to the hardware) it is not somewhere you should be writing to (because the address would 'belong' to something other than the code you are running in main).
You should only access addresses you have reason to know are valid (your assignValueTen function has such as an implicit requirement), C does not really have a way to enforce such requirement contracts though some other languages do.
Because when you do:
int main( void ){
int x;
assignValueTen(&x);
printf("The value of x is %d.\n",x);
return 0;
}
or:
int main( void ){
int x, *y;
y=&x;
assignValueTen(y);
printf("The value of x is %d.\n",x);
return 0;
}
you're always printing an int , while in the last example you're trying to print a pointer to an int, or at least that's the way i see it.

How to understanding pointers in functions

I have two files, main.c and main2.c. My experience tells me that they should do exactly the same, but they do not.
main.c declares a global variable outside the main routine. Then, inside the main routine, a pointer is declared and defined to point to that global variable. The global variable is changed, and the value of the local variable is printed to screen.
main2.c does the same, but convolutes local-to-global definition and change of global variable value into another function, change_number.
I cannot understand why this approach fails. main.c and main2.c are the boiled down results from a few hours of bugs fixing, documentation and tutorial reading and, obviously, reading here on SO.
My understanding of pointers is what I would call rudimentary: It points to a memory location. In case of a regular variable, the pointer would point to the memory location of that variable. Several pointers can point to the same memory location, but one pointer cannot point to several locations.
There's no such thing as pass-by-reference in C, but, as far as I know, this is not pass by reference since all variable and pointers are defined outside the function. Please enlighten me.
//File: main.c
#include <stdio.h>
#include <stdlib.h>
int global_number;
int main() {
int *local_number;
local_number = &global_number;
global_number = 9;
printf("local_number = %d\n", *local_number);
return 0;
}
Output: "local_number = 9". This is the expected result.
//File: main2.c
#include <stdio.h>
#include <stdlib.h>
int global_number;
void change_number(int *number) {
number = &global_number;
global_number = 9;
}
int main() {
int *local_number;
change_number(local_number);
printf("local_number = %d\n", *local_number);
return 0;
}
Output: "Segmentation fault". This is obviously not intended. The code runs fine right up until printf().
you never initialize local_number in the second program. It does not point anywhere, and will crash when accessed. Try
int *local_number = &global_number;
then the value should change
To have change_number also initialize local_number, pass the address of local_number and change the pointed-to pointer:
void change_number( int **number ) {
*number = &global_number;
global_number = 9;
}
...
int *local_number;
change_number(&local_number);

Why uninitialized local variable always has the same initial value?

In this piece of code, why in my testing the result is always 1, 2, and 3?
#include <stdio.h>
void test() {
int a;
a++;
printf("%d",a);
}
int main(int argc, char *argv[]) {
test();
test();
test();
}
I think the variable in test() is static, isn't it? And Why?
The variable is not static. You're accessing an uninitialized variable. The behavior is undefined.
As other answers told, your variable is not initialized.
It prints 1, 2 and 3 possibly because of your compiler compiled the code with prolog(prologue) that cleans the stack with zeros.
The local variables in C, actually point to the offset on your stack, and the stack frame will be restored after the call is returned.
I googled and selected a artical randomly that told about this, see [How function calls work?].
Here is a video talk about that [Assembly Programming Assembly Function Stack Frame Explained ] (again, selected randomly).
And Wikipedia explains the [Call stack] as well.
Because you are working with an unintialize value... (random behaviour in this case).
Initialize your variable (example to 0) :
#include <stdio.h>
void test(){
int a=0;
a++;
printf("%d",a);
}
int main(int argc, char *argv[]) {
test();
test();
test();
}
No, your variable is not static at all!
https://stackoverflow.com/a/1597426/1758762
Static variables (file scope and function static) are initialized to zero:
int x; // zero
int y = 0; // also zero
void foo() {
static int x; // also zero
}
Non-static variables (local variables) are indeterminate. Reading them prior to assigning a value results in undefined behavior.
void foo() {
int x;
printf("%d", x); // the compiler is free to crash here
}
the variable you are trying to print is not static and neither it is initialized , thus it is taking garbage value , which seems random to you , if you execute this program on a different machine ,then there you will have different output because there you will have different garbage value
in order to avoid it , you will have to initialize your variable with some value

simple pointers to pointers

I know why this works:
#include <stdio.h>
void cool_number(int **number) {
int value = 42;
int *p = &value;
*number = p;
}
int main () {
int *number;
cool_number(&number);
printf("number is %d\n", *number);
return 0;
}
What I don't understand is why this doesn't (in my machine it prints 3700 or something like that).
#include <stdio.h>
void cool_number(int **number) {
int value = 42;
int *p = &value;
int **x = &p;
number = x;
}
int main () {
int *number;
cool_number(&number);
printf("number is %d\n", *number);
return 0;
}
Why aren't both equivalent?
both are evil as they capture the address of a stack variable.
Second one doesn't do what you expect because you are assigning directly to the parameter number, which is only temporary, the first one changes something the parameter number pointers to, which is the same thing as number in main points to.
I assume they're not equivalent because number is passed by value, on the stack, as is standard for function parameters. Any changes that you make directly to number inside of cool_number() are modifying the local copy on the stack, and are not reflected in the value of number in main().
You get around this in the first example by dereferencing number, which tells the computer to modify some specific location in memory that you also happen to have a pointer to back in main(). You don't have this in the second example, so all that happens is that you make the local number pointer point to somewhere else, without actually updating any memory location being referred to back in main(). Thus nothing you do shows up once you get back to main().
And since value is local to the cool_number() function, setting a reference to it that will be accessed after cool_number() returns isn't guaranteed to work and certainly shouldn't be used in any code outside of a trivial/toy example. But in this specific instance it's not really related to why you're seeing different results between the two pieces of code.
As I understand, in both cases, your code is wrong.
In the first case, you are returning an address to a variable allocated on stack, which will be deallocated as soon as the function returns.
In the second case, the error of the first case exists, plus you are passing number by value, so an updation to number will not get reflected in the caller function.
In 'C', arguments are always passed by value. So, you cannot update the argument passed as it is. For Ex:
int func(int a)
{
a = 5; // In this case the value 5 will not be reflected in the caller as what is updated is the local copy of a on the stack
}
int func(int *a)
{
*a = 5; // This update will show in caller as you are directly updating the memory pointed to by a
a = malloc(4); //This update will not show in caller as again you are updating the local copy of stack
}
#include <stdio.h>
void cool_number(int **number) {
int value = 42; /* this "value" hold 42 value,
and it lifetime is only in this function */
int *p = &value; /* here we get the address of "value" in memory */
*number = p;
}
int main () {
int *number;
cool_number(&number); /* after this function the "value" in memory had been recyled
and may be used by other program */
printf("number is %d\n", *number); /* so when we print value here it will be
a unpredictable value, somehow may be crash */
return 0;
}
both the same principle

What is wrong with this C code

I have a piece of code where I am trying to return the square of the value pointed to by *ptr.
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
main()
{
int a=8,t;
t=square(&a);
printf("%d",t);
}
Its working fine for me but author of this code said it might not work because of following reason:
Because it's possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square!. The correct way to do is
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
I really wanted to know why he said like that?
The idea of the volatile keyword is exactly to indicate to the compiler that a variable marked as such can change in unexpected ways during the program execution.
However, that does not make it a source of "random numbers" - it just advises the compiler - what is responsible for actually changing the variable contents should be another process, thread, some hardware interrupt - anything that would write to the process memory but not inlined in the function where the volatile declaration finds itself. In "older times" (compilers with less magic) everything it did was preventing the compiler from caching the variable value in one of the CPU registers. I have no idea on the optimisations/de-optimistions strategies triggered by it by modern compilers - but it will at least do that.
In the absense of any such external factor, a "volatile" variable is just like any other. Actually - it is just like any other variable - as variables not marked as volatile can also be changed by the same external causes (but the compiled C code would not be prepared for that in this case, which might lead to incorrect values being used).
Since the question has an accepted and correct answer, I will be brief: here is a short program that you can run to see the incorrect behavior happening for yourself.
#include <pthread.h>
#include <math.h>
#include <stdio.h>
int square(volatile int *p) {
int a = *p;
int b = *p;
return a*b;
}
volatile int done;
void* call_square(void* ptr) {
int *p = (int*)ptr;
int i = 0;
while (++i != 2000000000) {
int res = square(p);
int root = sqrt(res);
if (root*root != res) {
printf("square() returned %d after %d successful calls\n", res, i);
break;
}
}
done = 1;
}
int main() {
pthread_t thread;
int num = 0, i = 0;
done = 0;
int ret = pthread_create(&thread, NULL, call_square, (void*)&num);
while (!done) {
num = i++;
i %= 100;
}
return 0;
}
The main() function spawns a thread, and modifies the data being squared in a loop concurrently with another loop calling the square with a volatile pointer. Relatively speaking, it does not fail often, but it does so very reliably in less than a second:
square() returned 1353 after 5705 successful calls <<== 1353 = 33*41
square() returned 340 after 314 successful calls <<== 340 = 17*20
square() returned 1023 after 5566 successful calls <<== 1023 = 31*33
First understand what's volatile: Why is volatile needed in C?
and then, try to find answer by yourself.
It's a game of volatile and hardware world. :-)
Read answer given by Chris Jester-Young:
volatile tells the compiler that your variable may be changed by other means, than the code that is accessing it. e.g., it may be a I/O-mapped memory location. If this is not specified in such cases, some variable accesses can be optimised, e.g., its contents can be held in a register, and the memory location not read back in again.
If there is more than one thread, the value the pointer points to might change inbetween statement "a = *ptr" and statement "b = *ptr". Also: you want the square of a value, why put it into two variables?
In the code you present then there is no way for the variable a that is defined in your main to be modified whilst square is running.
However, consider a multi-threaded program. Suppose that another thread modified the value to your your pointer refers. And suppose that this modification took place after you had assigned a, but before you had assigned b, in the function sqaure.
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
//the other thread writes to *ptr now
b = *ptr;
return a * b;
}
In this scenario, a and b would have different values.
The author is correct (if *ptr will be changed by other threads)
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
//between this two assignments *ptr can change. So it is dangerous to do so. His way is safer
b = *ptr;
return a * b;
}
Because the value of the pointer *ptr might change between the first affection and the second one.
I don't think the value of *ptr can change in this code barring an extremely unusual (and non-standards-compliant) runtime environment.
We're looking at the entirety of main() here and it's not starting up other threads. The variable a, whose address we are taking, is a local in main(), and main() doesn't inform any other function of that variable's address.
If you added the line mysterious_external_function(&a); before the t=square(&a) line, then yes, mysterious_external_function could start a thread and diddle the a variable asynchronously. But there's no such line, so as written square() always returns a square.
(Was the OP a troll post, by the way?)
I see some answers with *ptr can be changed by other threads. But this cannot happen since *ptr is not a static data variable. Its a parameter variable and local and parameter variables being hold inside stack. Each thread has its own stack section and if *ptr has been changed by another thread, it should not effect the current thread's.
One reason why the result might not give the square can be an HW interrupt might happen before assigning b = *ptr; operation as indicated below:
int square(volatile int *ptr) {
int a,b;
a = *ptr; //assuming a is being kept inside CPU registers.
//an HW interrupt might occur here and change the value inside the register which keeps the value of integer "a"
b = *ptr;
return a * b;
}

Resources