function that returns a pointer - c

I am refreshing my memory of C, and I wanted to test pointers.
I did this simple program, where I call a function that returns a pointer to the largest integer among it's arguments
int*function_pointer (int a, int b, int c);
int main ()
{
printf("Testing pointers\n");// line 1
int*pointer = pointer_function(10,12,36);
//pointer_function(10,102,36) is assigned to int*pointer
printf("Okay, what now...\n");//line 3
return 0;
}
the pointer function
int*function_pointer (int a, int b, int c)
{
int x;
int*ptr = &x;
//initially ptr points to the address of x
if(a > b)
{
if(a > c)
{
printf("a is the greatest\n);
ptr = &a;
}
}
if(b > a)
{
if(b > c)
{
printf("b is the greatest\n");
ptr = &b;
//b is 102, so in this scope ptr points to the address of b
}
}
if(c > a)
{
if(c > b)
{
printf("c is the greatest\n");
ptr = &c;
}
}
return ptr;
//function returns the value of ptr which is the address of b
}
at main function function_pointer(10,102,36) is called
inside function_pointer(...), int a, b, c are created for that scope
initially ptr = &x
since b = 102, ptr = &b
the functions returns the value of ptr
at main pointer = ptr, hence pointer = &b
but b is out of scope, and doesn't have any content
so how come *pointer = 102, shouldn't it return a garbage value since b is not withing the scope of the main function

but b is out of scope, and doesn't have any content
Your pointer is technically still valid and it just points to memory area. It your case it, when function_pointer() returns the b still points to memory it was using for local variable (so, in this case on your stack). You should not use the memory any longer, but as memory content your pointer points to is by default not zeroed when no longer used, then you are simply lucky to still have previous value 102 still there, because as your stack did not expand more than since function_pointer() returned as no other code needed to do that.
If you want do to do some tests, you may want to create another function that you call after function_pointer(). If that new function you need to local variables (i. e. array of 150 ints). to make your code to use more stack and overwrite leftovers. Then you will no longer see 102.

Related

Pointer value in c

Generally speaking, a pointer's value inside a function in c is local or can be accessed in main through the pointer?
Example code:
size_t *function(int a, int *b)
{
int d;
size_t *array;
b = &d;
//DO STUFF HERE
printf("%d", *b); //This gets printed right
return array;
}
int main()
{
size_t *array2;
int *b;
array2 = function(a, b);
printf("%d", *b); //This gives seg fault
}
Arguments are local variables, so you are not actually assigning to main's pointer, you are just ignoring the value passed as argument and assigning to the local b in function. You need a pointer to pointer int **b argument in order to assign to the b in main.
Also, the assigned address is that of a local variable d, which ceases to exist when function returns so accessing it afterwards through a pointer would be invalid regardless (undefined behaviour, even if it might happen to work before it gets overwritten on the stack).
edit: If your goal is to get the value of d to main, you don't need a pointer in main, so instead of b you can have int d in main and pass its address &d to function (function(a, &d)), then you can assign to main's d in function with *b = d.
In function main you pass the pointer b to function but b is uninitialized (can contain any value):
array2 = function(a, b);
Thefore this makes no sense. Inside function, If you want to modify b you need to instead call function like this:
int b;
array2 = function(a, &b);
The function can now assign to *b.
As Arkku says Arguments are local variables, you can treat the pointer as an address value like 0x7fff13f1ce3c, then it's pretty easy to understand.
typedef address int*
typedef address2 size_t*
size_t *function(int a, address b)
{
int d;
address2 array;
b = &d;
//DO STUFF HERE
printf("%d", *b); //This gets printed right
return array;
}
int main()
{
address2 array2;
address b;
array2 = function(a, b);
printf("%d", *b); //This gives seg fault
}
Change the value of b in function won't influence the value of b in main. As for the array, function will return An address value.

Questions about pointers in C language functions [duplicate]

This question already has answers here:
Pointers as function arguments in C
(7 answers)
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 3 years ago.
Under what circumstances, the pointer in the C language function will change after the function is executed, and under what circumstances will not change.
I am learning pointers now, but I am having some trouble now.
The first code
#include<stdio.h>
#include<stdlib.h>
void test(int* p);
int main()
{
int a[] = {2, 4, 6, 8, 0};
int* p = a;
printf("before p = %p, *p = %d\n", p, *p);
test(p);
printf("after p = %p, *p = %d\n", p, *p);
system("pause");
return 0;
}
void test(int* p)
{
p++;
printf("In test p = %p, *p = %d\n", p, *p);
}
The second code
#include<stdio.h>
#include<stdlib.h>
void swap (int* a, int* b);
int main()
{
int a, b;
scanf("%d %d", &a, &b);
swap(&a, &b);
printf("%d %d\n", a, b);
system("pause");
return 0;
}
void swap (int* a, int* b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
I want to know why p has not changed in the first program after the execution of the function, and the second program a, b has changed.
Variables in C have a value (content) and they have a memory address (location) - the address may be optimized away by the compiler when not in use.
C passes arguments to functions by value (always), so the arguments (variables) in the function occupy a different memory location (even if they are initialized with the same value).
The value of the pointer can be manipulated (p++), effecting its data (changing the location to which p is pointing).
Pointers can also be dereferenced (*p), effecting the data in the location they point to.
In the function test(int* p), the argument p is placed in the scope of the function. It can't accessed by other functions and it isn't available outside of the function (unless it's location is known by someone else, then they can access it).
When you edit the content of the p variable, it only effects the value of p within the function - it changes the location to which p is pointing.
However, when you dereference the value of p, you read / write to the location to which p is pointing (the location in the memory that holds the variable in main).
This is why the p++ in test doesn't effect the value in main.
On the other hand, in the swap function, you were writing to the memory that held the variables in main, which has side effects in main.

Why the value stored in 'z' is 35? Shouldn't it be 20 since in the function 'c=*b' (c is equal to the value pointed by *b)?

In the following code:
#include <stdio.h>
void shuffle(int* a, int* b, int c) {
int temp = *a;
*a = *b + c;
c = *b;
*b = temp;
}
int main() {
int x = 10;
int y = 20;
int z = 35;
shuffle(&x,&y,z);
printf("x: %i\n", x);
printf("y: %i\n", y);
printf("z: %i\n", z);
return 0;
}
The value of 'z' remains 35. Why is that so? Shouldn't the value be 20? Since:
c = *b;
When you pass a, b and c as parameters you can notice something, that int c is not passed as a pointer. In C the parameters can be passed two ways.
The first is reference-passed parameter, the parameter is passed as the address of the variable, any change done to the content of that address will persist even out of the function.
The second way is to pass it as a by-value parameter, in that case, you only create a copy of the content of the "passed" variable to another.
Now, int* a is passed as a reference (because it is a pointer), lets say a=0x12341234(address of a) and its value is 10, and one more time, int c (not a pointer) has 0x10101010 as an address with a value of 35.
Then, when our function is called with a as a pointer and c as a normal integer, we can realize that inside the function the address of a stills 0x12341234, however, address of c is now 0x20202020(for example). We have created a copy of c in another place of the memory. Modifying a copied variable does not modify the original variable. This is like:
int original = 20;
int copy = original;//we see that copy is a COPY of original
copy = 321;//Original still being 20

If p is a pointer to int where would one use &p

In the following code p is pointer to an int. It is quite clear that p points to the address of i. Through my research i know &p points to the address of pointer p. But i don't get why would you need separate address for that. And also when would you use &p.
int main() {
int i = 3, *p = &i;
printf("%p",&p);
printf("%p",p);
return 0;
}
If p is pointer to int then
int **q = &p;
When you want to use pointer to pointer, then use the address of a single pointer to assign it to pointer to pointer.
Just to make a point that pointer is also a data-type and it stored in the memory location and it holds a valid memory location as its value. The address in which this valid memory location is stored is given by &p
Your printf() also needs to be fixed. %p expects void *
printf("%p",(void *)p);
But i don't get why would you need separate address for that
You don't, but there exists the address of operator so you can take the address of a pointer, which is what
printf("%p\n", &p);
is printing.
And also when would you use &p
There are cases where this might be useful, consider for example that you need to pass a pointer to a function which could be reassigned into the function, you can do something like this
int allocateIntegerArray(int **pointerToPointer, size_t someSize)
{
if (pointerToPointer == NULL)
return 0;
*pointerToPointer = malloc(someSize * sizeof(int));
return (*pointerToPointer != NULL);
}
then you could use this funciton the following way
int *pointer;
if (allocateIntergerArray(&pointer, 10) == 0)
{
fprintf(stderr, "Error, cannot allocate integer array\n");
/* do some extra cleanup or recover from this error, or exit() */
exit(0);
}
The pointers themselves are also variables and as such they need to be sotred somewhere, so the address of a pointer tells you where is the pointer stored, it's value tells you where it is pointing to.
By knowing where it is stored you can do things like the one explained above.
A trivial example:
int nochange(int *c, int *val)
{
c = val; // Changes local pointer c to point to val
// Note that C passes copies of the arguments, not actual references.
}
int do_change(int **c, int *val)
{
*c = val; // Accesses the real pointer c at its real location and makes
// that one point to val
// Even though c is a pointer-to-pointer copy, its value is
// copied too, and the value is the address of the real c
}
int main()
{
int a = 1;
int b = 2;
int *c = &a; // A pointer is also a datatype that resides in memory
printf("%d\n", *c); // Will print 1
nochange(c, &b);
printf("%d\n", *c); // Will print 1
do_change(&c, &b);
printf("%d\n", *c); // Will print 2 because c now points to b
}
I have a similar answer with a bit more detail here about pointer vs pointer-to-pointer: pointer of a pointer in linked list append

Value pointed to by a pointer changes after first dereference

I am trying to initialize the integer pointer "p" inside the "init_pointer" function. After the function returns I am printing the pointer and the dereferenced value twice. The first dereference prints the expected value 100, but the second dereference prints random values.
#include<stdio.h>
void init_pointer(int d, int **c){
(*c) = &d;
}
int main(){
int x = 100;
int *p;
init_pointer(x,&p);
printf("pointer = %p, value = %d\n",p,*p);
printf("pointer = %p, value = %d\n",p,*p);
return 0;
}
Output:
pointer = 0x7fffb4d4b9ac, value = 100
pointer = 0x7fffb4d4b9ac, value = 32567
The function has copied the value to a new local variable in init_pointer(int d, int **c)
d is local to init_pointer which was passed by main from x. Both x and d are separate variables whose addresses are different. Accessing the address of d outside init_pointer will lead to Undefined Behavior.
It would not make sense to call the function like this but this will work:
void init_pointer(int *d, int **c)
{
(*c) = d;
}
int main()
{
int x = 100;
int *p;
init_pointer(&x,&p);
printf("pointer = %p, value = %d\n",p,*p);
printf("pointer = %p, value = %d\n",p,*p);
return 0;
}
Output:
pointer = 0xbfde132c, value = 100
pointer = 0xbfde132c, value = 100
void init_pointer(int d, int **c){
(*c) = &d;
}
Here *c points to a local copy inside init_pointer(). Once init_pointer() returns, the address becomes invalid, and p in main() points to a freed address.
In init_pointer you assign the address of the parameter d to *c. The address of the parameter is a stack address.
In the first call to printf, the stack (although deallocated) is still intact, so p points to the discarded parameter d on the stack, which still has a value of 100, and *p is pushed first onto the stack.
In the second call to printf, the first call has overwritten the stack. Although the pointer still points to the same address, its value there has been overwritten by the push of p. Hence p (an address) is printed.
Notes: with "the stack (although deallocated)" I mean the stack of and below sp (intel; growing downward). Also, the stack can have been overwritten at any time, e.g. when interrupts occur.

Resources