Tricky C exercise related to pointers. Need help in understanding the solution - c

Consider the following code:
int *foo (int x) {
int a[2];
a[0] = x;
a[1] = x + 1;
return a;
}
…
int *p1 = foo(2);
int *p2 = foo(3);
At the conclusion of this code snippet, what are the values of each of the following? (answer is given)
p1[0] = 3
p1[1] = 4
p2[0] = 3
p2[1] = 4
Since a is allocated on the stack, the memory does not remain allocated when the call returns and may be reused by something else. In this case, since foo(3) is called immediately after foo(2) at the same call depth (i.e. they use the same stack space), they will both return the same pointer– i.e. p1 is equal to p.
I did not understand the above explanation. What does it really mean? Why we have exact same values for p2 and p1? I know that you cannot return a pointer to a local variable in C..but I do not understand why p2 and p1 has same values ....

Using a pointer to automatic storage variables (variables scoped to functions) outside its scope is undefined, which is exactly why you should never do it, and never depend on its behavior.
However, if you want to peel back the cover on the compiler/machine/os, the reason is that the automatic storage happens to be allocated at the same address for the two function calls.
An example...
#include "stdio.h"
int* foo(int x) {
int a[2];
printf("&a[0] = %p\n", &a[0]);
printf("&a[1] = %p\n\n", &a[1]);
a[0] = x;
a[1] = x + 1;
return a;
}
int main(int argc, char* argv[]) {
printf("foo(2)\n");
int* p1 = foo(2);
printf("foo(3)\n");
int* p2 = foo(3);
printf("p1[0] = %i\n", p1[0]);
printf("p1[1] = %i\n\n", p1[1]);
printf("p2[0] = %i\n", p2[0]);
printf("p2[1] = %i\n", p2[1]);
return 0;
}
outputs...
foo(2)
&a[0] = 0x7fff4dd0f054
&a[1] = 0x7fff4dd0f058
foo(3)
&a[0] = 0x7fff4dd0f054
&a[1] = 0x7fff4dd0f058
p1[0] = 3
p1[1] = 4
p2[0] = 3
p2[1] = 4
So, &a[0] and &a[1] have the same addresses in both foo(2) and foo(3).
What's happening is that when you enter a function, it generally creates a stack frame (by decrementing the stack pointer on x86). This allocates memory on the stack for automatic storage variables. When you leave the function, the stack frame is destroyed (and the stack pointer returned to its original value). So if you enter the same function again, you generally use the same memory for the stack frame (stack pointer is decremented to same value as last call to function).

it is undefined behavior, your program might crash too.
The local variable is stored on the stack and its life time is only with in the scope of the function.
In your case, the program is reusing the same location the next time , so your values are overwritten, but it is not always going to be same and never return address of local variable.

After each function call memory is allocated on stack for function variables and stack pointer is moved forward. After function execution stack memory is not erased for efficiency reasons and all data stays there. So if you call same function second time and leave some variables uninitialized you can find some funny values from last function call. Every array in C is stored as a big chunk of memory where elements are found by shifting pointer.
As for you question: foo returns pointer to integer, which is actually a memory address.
After foo(2) p1 will store some address for example 0x00. Adding braces [] with index to a integer pointer means to add an integer size * index to a memory address. We may add any random index to pointer and try to get data from there. If we get lucky and memory is readable - we will have some garbage data. After first function call
p1 points to a stack array and values are:
p1[0] == 2;
p2[1] == 3;
p1 == 0x00; (for example)
Function is executed and it returns stack pointer back. Next function call foo(3) gets same memory chunk on stack. Second call rewrites variables with new values. After second call we get:
p2[0] == 3;
p2[1] == 4;
p2 == 0x00; (same memory address)
The problem is that p1 points to same memory address on stack. If you call any other function - both p1 and p2 will be changed again, because same region of stack will be reused again.

Stack unwind while returning from the function call will release the memory allocated for the array. That memory is no longer available. The behavior is undefined.

In your function foo() you have a local variable and your are trying to return the address of the local variable. Don't your compiler throw the below error:
warning: function returns address of local variable
If you have to get the answer you have posted then you need to make the array int a[2] global.
Else we have an undefined behavior here.

Related

Double Pointer and Local Scope Confusion

I am taking a c programming course on Udemy and am quite confused when passing a double pointer into a function. In the example, the instructor passes the address of a pointer as an argument to a function. Then, he de-references that double pointer parameter in the function and sets it equal to the address of a local variable (a).
#include <stdio.h>
#include <malloc.h>
void foo(int **temp_ptr)
{
int a = 5;
*temp_ptr = &a;
}
int main()
{
int *ptr = NULL;
ptr = (int*) malloc(sizeof(int));
*ptr = 10;
foo(&ptr);
printf("%d\n", *ptr);
return 0;
}
So, what we are doing here is changing the value of ptr to hold the address of a. Then, when we de-reference ptr, it should display the value of 5 and not 10, since we changed the value of ptr to hold the address of a.
This is indeed correct: it displays 5 and not 10.
However, what doesn't make sense here is that the variable a is in the local scope of the foo function. When we declare a, the memory allocated is put onto the stack frame; thus, when leaving the local scope of the function that memory is deleted and the frame is popped off of the stack. How can we still access that variable a with the ptr variable in the main function? Shouldn't that memory be completely wiped out?
Then, when we de-reference ptr, it should display the value of 5
Should is incorrect. printf("%d\n", *ptr); is undefined behavior (UB) as the address stored in ptr is invalid with the return of foo(&ptr);.
Output may print 5, may print 42, may crash. It is UB.
... correct that the memory of the stack should be completely wiped out
No. There is not specified wiping of memory. The result is UB.
But sometimes undefined behavior works?
"undefined behavior" is undefined. Even if it "works" today, it may not "work" tomorrow.
When we declare a, the memory allocated is put onto the stack frame; thus, when leaving the local scope of the function that memory is deleted and the frame is popped off of the stack.
This assumes an underling code model that is not specified by C. Other real possibilities exist.
How can we still access that variable a with the ptr variable in the main function?
As is, no defined way. Alternatively keep the address of a valid by making a static.
In Foo function, we are updating the address of our pointer. int a declared in foo function will be stored at some memory location. Now, we are assigning that location to our ptr(which is okay, ptr can point to any memory location of type int). But the issue is the value at that location is not in our control and this location can be used for any other purpose which may update the value at that location.
It means that our pointer is now pointing to location that may be updated by any other source.

How do I use pointers? in C

Im fairly new to C programming and I am confused as to how pointers work. How do you use ONLY pointers to copy values for example ... use only pointers to copy the value in x into y.
#include <stdio.h>
int main (void)
{
int x,y;
int *ptr1;
ptr1 = &x;
printf("Input a number: \n");
scanf("%d",&x);
y = ptr1;
printf("Y : %d \n",y);
return 0;
}
It is quite simple. & returns the address of a variable. So when you do:
ptr1 = &x;
ptr1 is pointing to x, or holding variable x's address.
Now lets say you want to copy the value from the variable ptr1 is pointing to. You need to use *. When you write
y = ptr1;
the value of ptr1 is in y, not the value ptr1 was pointing to. To put the value of the variable, ptr1 is pointing to, use *:
y = *ptr1;
This will put the value of the variable ptr1 was pointing to in y, or in simple terms, put the value of x in y. This is because ptr1 is pointing to x.
To solve simple issues like this next time, enable all warnings and errors of your compiler, during compilation.
If you're using gcc, use -Wall and -Wextra. -Wall will enable all warnings and -Wextra will turn all warnings into errors, confirming that you do not ignore the warnings.
What's a pointer??
A pointer is a special primitive-type in C. As well as the int type stored decimals, a pointer stored memory address.
How to create pointers
For all types and user-types (i.e. structures, unions) you must do:
Type * pointer_name;
int * pointer_to_int;
MyStruct * pointer_to_myStruct;
How to assing pointers
As I said, i pointer stored memory address, so the & operator returns the memory address of a variable.
int a = 26;
int *pointer1 = &a, *pointer2, *pointer3; // pointer1 points to a
pointer2 = &a; // pointer2 points to a
pointer3 = pointer2; // pointer3 points to the memory address that pointer2 too points, so pointer3 points to a :)
How to use a pointer value
If you want to access to the value of a pointer you must to use the * operator:
int y = *pointer1; // Ok, y = a. So y = 25 ;)
int y = pointer1; // Error, y can't store memory address.
Editing value of a variable points by a pointer
To change the value of a variable through a pointer, first, you must to access to the value and then change it.
*pointer1++; // Ok, a = 27;
*pointer1 = 12; // Ok, a = 12;
pointer1 = 12; // Noo, pointer1 points to the memory address 12. It's a problem and maybe it does crush your program.
pointer1++; // Only when you use pointer and arrays ;).
Long Winded Explanation of Pointers
When explaining what pointers are to people who already know how to program, I find that it's really easy to introduce them using array terminology.
Below all abstraction, your computer's memory is really just a big array, which we will call mem. mem[0] is the first byte in memory, mem[1] is the second, and so forth.
When your program is running, almost all variables are stored in memory somewhere. The way variables are seen in code is pretty simple. Your CPU knows a number which is an index in mem (which I'll call base) where your program's data is, and the actual code just refers to variables using base and an offset.
For a hypothetical bit of code, let's look at this:
byte foo(byte a, byte b){
byte c = a + b;
return c;
}
A naive but good example of what this actually ends up looking like after compiling is something along the lines of:
Move base to make room for three new bytes
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable b) to the value of b
Set mem[base+2] (variable c) to the sum mem[base+0] + mem[base+1]
Set the return value to mem[base+2]
Move base back to where it was before calling the function
The exact details of what happens is platform and convention specific, but will generally look like that without any optimizations.
As the example illustrates, the notion of a b and c being special entities kind of goes out the window. The compiler calculates what offset to give the variables when generating relevant code, but the end result just deals with base and hard-coded offsets.
What is a pointer?
A pointer is just a fancy way to refer to an index within the mem array. In fact, a pointer is really just a number. That's all it is; C just gives you some syntax to make it a little more obvious that it's supposed to be an index in the mem array rather than some arbitrary number.
What a does referencing and dereferencing mean?
When you reference a variable (like &var) the compiler retrieves the offset it calculated for the variable, and then emits some code that roughly means "Return the sum of base and the variable's offset"
Here's another bit of code:
void foo(byte a){
byte bar = a;
byte *ptr = &bar;
}
(Yes, it doesn't do anything, but it's for illustration of basic concepts)
This roughly translates to:
Move base to make room for two bytes and a pointer
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable bar) to the value of mem[base+0]
Set mem[base+2] (variable ptr) to the value of base+1 (since 1 was the offset used for bar)
Move base back to where it had been earlier
In this example you can see that when you reference a variable, the compiler just uses the memory index as the value, rather than the value found in mem at that index.
Now, when you dereference a pointer (like *ptr) the compiler uses the value stored in the pointer as the index in mem. Example:
void foo(byte* a){
byte value = *a;
}
Explanation:
Move base to make room for a pointer and a byte
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable value) to mem[mem[base+0]]
Move base back to where it started
In this example, the compiler uses the value in memory where the index of that value is specified by another value in memory. This can go as deep as you want, but usually only ever goes one or two levels deep.
A few notes
Since referenced variables are really just numbers, you can't reference a reference or assign a value to a reference, since base+offset is the value we get from the first reference, which is not stored in memory, and thus we cannot get the location where that is stored in memory. (&var = value; and &&var are illegal statements). However, you can dereference a reference, but that just puts you back where you started (*&var is legal).
On the flipside, since a dereferenced variable is a value in memory, you can reference a dereferenced value, dereference a dereferenced value, and assign data to a dereferenced variable. (*var = value;, &*var, and **var are all legal statements.)
Also, not all types are one byte large, but I simplified the examples to make it a bit more easy to grasp. In reality, a pointer would occupy several bytes in memory on most machines, but I kept it at one byte to avoid confusing the issue. The general principle is the same.
Summed up
Memory is just a big array I'm calling mem.
Each variable is stored in memory at a location I'm calling varlocation which is specified by the compiler for every variable.
When the computer refers to a variable normally, it ends up looking like mem[varlocation] in the end code.
When you reference the variable, you just get the numerical value of varlocation in the end code.
When you dereference the variable, you get the value of mem[mem[varlocation]] in the code.
tl;dr - To actually answer the question...
//Your variables x and y and ptr
int x, y;
int *ptr;
//Store the location of x (x_location) in the ptr variable
ptr = &x; //Roughly: mem[ptr_location] = x_location;
//Initialize your x value with scanf
//Notice scanf takes the location of (a.k.a. pointer to) x to know where
//to put the value in memory
scanf("%d", &x);
y = *ptr; //Roughly: mem[y_location] = mem[mem[ptr_location]]
//Since 'mem[ptr_location]' was set to the value 'x_location',
//then that line turns into 'mem[y_location] = mem[x_location]'
//which is the same thing as 'y = x;'
Overall, you just missed the star to dereference the variable, as others have already pointed out.
Simply change y = ptr1; to y = *ptr1;.
This is because ptr1 is a pointer to x, and to get the value of x, you have to dereference ptr1 by adding a leading *.

The following C program regarding pointers is not working

#include<stdio.h>
int main(void)
{
int *pc;
*pc=100;
printf("\n Address of Pointer : %d",pc);
printf("\n Contents of Pointer : %d",*pc);
}
When I run the code in eclipse, it is saying "Pointers.exe has stopped working". What is the error?
Assigning a value to *pc is particularly dangerous. If pc contains the valid memory address , then the assignment
*pc = 100;
will attempt to modify the data stored at that address.
If the location modified by this assignment belongs to the program, it may behave erratically; if it belongs to operating system, the program will most likely crash.
Your compiler should raise a warning that pc is uninitialized.
Change it to:
int a;
int *pc;
pc = &a;
*pc = 100;
Your pc pointer was not initialized in your program.
Moreover the way your are printing a pointer value is incorrect, use this:
printf("\n Address of Pointer : %p", (void *) pc);
You forgot to point pc to somewhere useful. When you write
int *pc;
The compiler creates a pointer for you. The pointer points somewhere in memory, and you have no way of knowing where. Chances are, it points to a bad place in memory. When you overwrite it with *pc=... you overwrite a place in memory that shouldn't be overwritten.
So you need to have pc point somewhere.
int a, *pc=&a;
will do the trick. Now the compiler prepares an int for you then and you point pc to it. That way, when you write through the pointer, nothing bad will happen - you're writing on an area of memory that you know is safe.
Another way to initialize pc is like so:
int *pc = (int*)malloc(sizeof(int)); // Allocate an integer on the heap
Now *pc=100; will also work. Just don't forget to free(pc) when you're done.
You have:
int *pc;
*pc=100;
When you define the pointer to integer pc above, this pointer is not initialized, so it points to some memory that you have not allocated and you have not the right to access.
So your executable is crashing.
Just use a valid pointer, e.g. you can allocate some heap memory using malloc(sizeof(int)) (and later release it using free()), or just use stack-based memory for local automatic variables, e.g.:
/* An integer stack-allocated variable */
int n = 64;
/* Pointer to that integer */
int * pn = &n;
/* Change its value */
*pn = 100;
Moreover, to print an address, considering using the %p specifier for printf().
e.g.:
#include <stdio.h>
int main(void)
{
int n = 64;
int *pn = &n;
printf("n (before): %d\n", n);
*pn = 100;
printf("n (after): %d\n", n);
printf("Address of n: %p", (void *)pn);
return 0;
}
Output:
n (before): 64
n (after): 100
Address of n: 003AF7CC
Pointers need to POINT! A pointer is a variable that contains the adress of another variable.
int *pc;
This pointer contains some garbage value. Who knows what was in that memory before. The adress that it's pointing to could be an adress of memory that is occupied by another program. You need to assign a valid adress to a pointer if you want to change the value in that adress.
If you want to calculate sum of all the members of an array you would have to initialize the variable sum to 0 because it could contain other values.
The same is with pointers. They have to contain a valid adress of a variable if you want to modify the value.
Your program would work if you comment line *pc = 100;. You can display the adress of an uninitialized pointer but the program will crash if you try to change the value in that adress.

Exact output of free() in C?

I wanted to ask, if I have a pointer pointing at some struct, but then I free(struct) then if I dereference the pointer, will it be pointing to NULL? As in can I check, pointer != NULL or is this undefined?
Thanks!
Calling free() on the pointer does not change the pointer value. It will still point to the same memory that no longer belongs to your application. You should always assign NULL to a free'd pointer immediately after you free it to ensure that you don't use it again.
void *p = malloc(10); // p points to allocated memory
free(p); // p still points to invalid memory
p = NULL; // good practice
Consider the below code
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
free(p);
}
Here variable p is a local variable of a function main. Size of this variable will be 4 bytes(in 32bit m/c) or 8 bytes(in 64 bit m/c). Now we are allocating memory for storing 10 integer elements and that address is stored in variable p. Now we are calling free function to which we are passing the dynamic memory address which is stored in the local variable p. Now free function will free the memory and it will not be able to assign NULL to the variable p. Because we passed address as value, not reference to the pointer.
We can define a wrapper function for free like below
void myfree(void **p)
{
free(*p);
*p = NULL;
}
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
myfree(&p);
}
Or we can define macro function also
#define MYFREE(x) \
free(x); \
x = NULL;
It's undefined. C does not define what it does with the contents of the pointer, although most implementations do nothing.
Take a look at this page.
It clearly says:
Notice that this function leaves the value of ptr unchanged, hence it
still points to the same (now invalid) location, and not to the null
pointer.
Note that it is up to you to make sure that pointer is not dereferenced after being freed.

C pointers and memory

I'm learning C and now I hit a wall. Its difficult for me to understand pointers.
Imagine I have this code:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define DELTA 33
int calls, seed=356;
int sum_ds(int a){
int d=DELTA;
calls++;
return a+d+seed;
}
int main() {
int num;
int *ptr;
int **handle;
num = 14;
ptr = (int *)malloc(2 * sizeof(int));
handle = &ptr;
*(*handle+0) = num;
*(*handle+1) = num+1;
*ptr = num-2;
ptr = &num;
*ptr = sum_ds(num-2);
}
Lets go step by step trough my understanding.
1 - int calls creates a variable named calls and doesn't initializes it so it contains rubbish. It is stored on DATA and let's say with the memory address 0xFFAA.
2 - int seeds creates a variable named seeds initialized with the integer 356. It is stored on DATA and let's say with the memory address 0xFFAB.
3 - int num creates a variable named num and doesn't initializes it so it contains rubbish. It is stored on the STACK and let's say with the memory address 0xFFAC.
4 - int *ptr creates a pointer to int and does not assign any address to it. It is stored on the STACK and let's say with the memory address 0xFFAD.
5 - int **handle creates a pointer to a pointer of int and does not assign any address to it. It is stored on the STACK and let's say with the memory address 0xFFAE. (MANY DOUBTS HERE)
6 - num = 14 goes to the address 0xFFAC and stores the number 14 on it. It's done in the STACK.
7 - ptr = (int *)malloc(2 * sizeof(int)) On the HEAP it's assigned memory size for 2 ints and the address of the first memory byte (let's say 0xFFZZ) is stored (on STACK) on ptr so now *ptr points to that memory address.
8 - handle = &ptr handle now points to ptr. I believe it now points to whatever is on 0xFFZZ (MANY DOUBTS HERE)
9 - *(*handle+0) = num the pointer to the pointer of int now its assigned with the value of num (14) (MANY MANY MANY MANY DOUBTS HERE)
10 - *(*handle+1) = num+1 the pointer of pointer plus one of int now its assigned with the value of num + 1 (15) (MANY MANY MANY MANY DOUBTS HERE)
11 - *ptr = num-2 the value point by ptr it's assigned with the value of num - 2 (12). I believe it goes to the memory address 0xFFZZ and stores there the number 12.
12 - ptr = &num ptr now points to num, i believe it now points to 0xFFAC.
13 - *ptr = sum_ds(num-2) the value pointed by ptr is the returned value of sum_ds. I belive 0xFFAC it's assigned with 401 (12+33+356)
Is this right?
1 - int calls creates a variable named calls and doesn't initializes it so it contains rubbish. It is stored on DATA and let's say with the memory address 0xFFAA.
2 - int seeds creates a variable named seeds initialized with the integer 356. It is stored on DATA and let's say with the memory address 0xFFAB.
One little detail: sizeof(int) is greater than 1 (it is 4 on most mainstream platforms, so the 2nd address could not be 1 higher than the 1st. Other than that, AFAIK you are correct so far.
3 - int num creates a variable named num and doesn't initializes it so it contains rubbish. It is stored on the STACK and let's say with the memory address 0xFFAC.
4 - int *ptr creates a pointer to int and does not assign any address to it. It is stored on the STACK and let's say with the memory address 0xFFAD.
Another little detail: on most mainstream platforms, the stack grows downward, so the 4th address would be less than the 3rd. Other than that, AFAIK you are correct so far. (Moreover, addresses on the data segment, the heap and the stack would be rather different in real life.)
7 - ptr = (int *)malloc(2 * sizeof(int)) On the HEAP it's assigned memory size for 2 ints and the address of the first memory byte (let's say 0xFFZZ) is stored (on STACK) on ptr so now *ptr points to that memory address.
To be nitpicky, 'Z' is not a hexadecimal number :-) So let's say it is 0x1000 instead.
8 - handle = &ptr handle now points to ptr. I believe it now points to whatever is on 0xFFZZ (MANY DOUBTS HERE)
No, handle now contains the address of ptr, that is 0xFFAD. Indirectly though - through ptr - it indeed points to 0x1000 (was 0xFFZZ in your example).
9 - *(*handle+0) = num the pointer to the pointer of int now its assigned with the value of num (14) (MANY MANY MANY MANY DOUBTS HERE)
Basically correct. The notation you use is not the easiest to deal with, which makes it more difficult for you to follow what's going on. After step 8, *handle is equivalent to ptr. And due to pointers and arrays being interchangeable in many common situations, *(ptr+0) is equivalent to ptr[0], and also to *ptr.
10 - *(*handle+1) = num+1 the pointer of pointer plus one of int now its assigned with the value of num + 1 (15) (MANY MANY MANY MANY DOUBTS HERE)
Similar to the previous point, you are in effect assigning ptr[1] = num+1. Keep in mind though that ptr is int*, so the address difference between ptr and ptr + 1 equals to sizeof(int), which is, as mentioned above, usually 4.
11 - *ptr = num-2 the value point by ptr it's assigned with the value of num - 2 (12). I believe it goes to the memory address 0xFFZZ and stores there the number 12.
Yes, this overwrites the value set in step 9.
12 - ptr = &num ptr now points to num, i believe it now points to 0xFFAC.
Correct.
13 - *ptr = sum_ds(num-2) the value pointed by ptr is the returned value of sum_ds. I belive 0xFFAC it's assigned with 401 (12+33+356)
Correct. Since the previous step made *ptr equivalent to num, this call is also equivalent to num = sum_ds(num-2).
Since calls is outside any function, it's a static variable. Static variables are initialized to 0.
Since num is a local variable (auto storage class) it is not initialized.
At your point 9, *(*handle+0) = num; is probably easiest to decipher by keeping in mind that handle = &ptr, therefore *handle = ptr, so this is basically equivalent to *(ptr+0) = num;, which is (in turn) equivalent to ptr[0] = num;.
For point 10, you get pretty much the same thing, except a +1 in both cases, so it's saying ptr[1] = num+1;.
For point 11, *ptr=num-2; overwrites what was written in point 9 -- i.e., *ptr is the same as *(ptr+0), so this is equivalent to ptr[0] = num-2;
You're correct in point 12 that ptr has been set to point at num. That means in point 13, the assignment is equivalent to num=sum_ds(num-2);
A variable has an address and stores at that address are the value that you just put:
int a = 10;
Right?
A pointer is a kind of variable that stores the address of another variable.
So...
int a = 10;
int *p = &a;
This means that "p" stores the address of "a" that has the value that you want to use.
Execute this code below and you'll understand:
printf("%p %p %d %d\n", p, &a, *p, a);

Resources