Questions about pointers in C language functions [duplicate] - c

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.

Related

Can I change the address of the pointer variable in C language?

For example, if there is a pointer variable int *a, int *b and each address value is 1000, 2000, can the address value of the pointer variable be swapped as if it were swapping the value of the common variable?
Note, I mean the address of the pointer. Not the value it contains.
As far as I know, the address value of the pointer variable is fixed and cannot be changed, is that right?
From comments:
A lot of people answered, but I think I asked the wrong question. I'm sorry, but my question is not about "change content of a pointer variable", but "change address of a pointer variable."
No, that's impossible for any variable. Not just pointers.
Can I change the address of the pointer variable in c language?
While the answer to your question would be yes for many other languages, including C++, kind of:
"While C++ doesn't directly support putting a variable at a given address, the same effect can be achieved by creating a reference to
that address:"...
...the answer for C is No. "A pointer has an address like other variables (which can't and needn't be changed)". (quote from 4th response in link.)
For C, the address of all variables (with the exception of those declared as register) are assigned at the time of declaration as a memory location provided by the operating system, and are immutable for the remainder of their life, no matter the scope in which they were created.
So, while the address pointed to by a pointer variable can be changed, the address of the variable itself, cannot.
Yes, you can:
void swapPointers(void **a, void **b) {
void *t = *a;
*a = *b;
*b = t;
}
void someOtherFunc() {
int *x = malloc(sizeof(int));
int *y = malloc(sizeof(int));
*x = 3;
*y = 5;
printf("x = %d y = %d\n", *x, *y);
swapPointers(&x, &y);
printf("x = %d y = %d\n", *x, *y);
}
Yes, you can swap the address the pointer points to.
int main()
{
int x = 5, y = 10;
int* p1 = &x;
int* p2 = &y;
printf("Address pointed by p1 is: %p\n", p1);
printf("Address pointed by p2 is: %p\n", p2);
//Here goes the swapping
int* p3 = p1;
p1 = p2;
p2 = p3;
printf("\n--After swap--\n");
printf("Address pointed by p1 is: %p\n", p1);
printf("Address pointed by p2 is: %p\n", p2);
}
I think you mean swapping addresses stored in pointers because you can not swap addresses of pointers as declared variables themselves.
To swap two objects in a function you have to pass them by reference. Otherwise the function will deal with copies of the values of passed directly to it objects.
In C passing by reference means passing an object indirectly through a pointer to it.
Pointers are the same objects.
So you can write the swap function the following way
void swap_ptr( int **a, int **b )
{
int *tmp = *a;
*a = *b;
*b = tmp;
}
And the function can be called like
int *a = /*...*/;
int *b = /*...*/;
//...
swap_ptr( &a, &b );
yes you can you just need to swap where each pointer point to.
declare a 3rd pointer then do the swap as follow.
//we have *a and *b
int *tmp;
tmp = a;
a = b;
b = tmp;
yes you can swap the address stored in two pointer using a temporary pointer variable. But if the pointer is declared as constant pointer for exapmle const int *ptr1; then it not possible because the address stored in ptr1 cannot be modified
#include <iostream>
using namespace std;
int main() {
int a=10;
int b=20;
int *ptr1;
int *ptr2;
ptr1=&a;
ptr2=&b;
cout<<ptr1<<" "<<ptr2<<"\n";
int *temp;
temp=ptr1;
ptr1=ptr2;
ptr2=temp;
cout<<ptr1<<" "<<ptr2;
return 0;
}
you can change the syntax to c because I thought that I was answering a question from c++ section

Why does a pointer "forget" its value despite pointing to malloc'ed memory [duplicate]

This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 3 years ago.
void init(int *a) {
int *b = malloc(sizeof(int));
*b = 4;
a = b;
printf("b address %d\n", b);
printf("a address %d\n", a);
printf("%d\n",*a);
}
int main()
{
int *a = malloc(sizeof(int));
printf("a address %d\n", a);
init(a);
printf("a address %d", a);
return 0;
}
will print the output
a address 32206864
b address 32211008
a address 32211008
4
a address 32206864
Here, the init function is initializing the value for a. However, this is done is incorrect and I am trying to determine why. Observe that once the init function ends the pointer a forgets the address it's supposed to point to. I assume this has something to do with the fact that a is set to b, a pointer that gets popped off the stack once the function ends.
But why does this make sense? Shouldn't a remember what memory address it's been set to? After all, the scope of a is the main function, not the init function.
The a in the function init and the a in main are different objects. The call init(a) only passes the value of a to the function. That value is only a copy of the value in the a in main. The init function does not receive any reference to the a in main.

In the following program the invocation of change_it() seems to have no effect. Please explain and correct the code? [duplicate]

This question already has answers here:
How to change a variable in a calling function from a called function? [duplicate]
(3 answers)
Closed 4 years ago.
void change_it(int[]);
int main()
{
int a[5],*p=1;
void change_it(int[]);
printf("p has the value %u \n",(int)p);
change_it(a);
p=a;
printf("p has the value %u \n",(int)p);
return 0;
}
void change_it(int[]) {
int i=777, *q=&i;
a = q; // a is assigned a different value
}
For starters, when you initialize p, you're giving a pointer the value of 1, when it needs a memory location. NULL uses 0, but that doesn't mean you can -or should- just assign integer values to pointers.
Just as an fyi, you can cast the value of 1 like this:
int a[5], *p = (int *) 1;
There's like -2 reasons for doing this, though, the -1th reason being that the minimal type safety that C provides should be respected, and the -2th being that it makes the code hard to understand for other people.
I'm going to assume what you meant to do was not declare a pointer with an address value of 1 though, and say you meant to declare a pointer that holds a value of 1. Unless you have another variable that holds the value of 1 already, you're going to have to first dynamically allocate the pointer, then set its value.
int* p = malloc(sizeof(int));
*p = 1;
If you had another variable to use, you could instead create the pointer on the stack rather than dynamically allocating it, like this:
int* q;
q = p;
Now, calling the same print function on both would yield this:
printf("p has the value %d\n", *p);
printf("q has the value %d\n", *q);
Output:
p has the value 1
q has the value 1
Addressing your main problem, you need to name the parameter in the change_it function, for example:
void change_it(int arr[])
Your program needs the parameter to be named, otherwise it has no idea of knowing you're trying to reference the array. The a variable you reference in the function is not bound to anything; the compiler will know be able to deduce what you're talking about.
Also, you don't need to redeclare the function prototype in your main function. The reason this is not a compiler error is that you can have as many declarations as you want, but only one definition. Again though, there's no reason to do this.
Another fyi, you don't have to name the parameters in your function prototypes, but it's good practice to both name them and be consistent with the names between the prototypes and the actual implementations so that people reading your code understand what's going on.
Also, you're using the %u specifier for the printf function, when you're not actually using unsigned decimal numbers. You're using signed decimals so you should use %d.
Lastly, your change_it function commits one crucial error preventing it from correctly changing the value of the passed-in array properly: you're setting the array that you passed in to the value of q.
Look at the function in your original code closely (pretend you named the input array a, as it looks like you mean to). You first declare an integer variable i and set its value to 777. Then, you create an integer-pointer variable q on the stack and correctly set its value to i. Note: You're not setting q to the value of i, but rather the address of i.
Why does this small but significant distinction matter? When you set a to q in the next line, you're changing the address of the array, specifically the first element of a five-element integer array, to point to the address of an integer variable. This is bad for a few reasons. First, the array is five integers long, but now it points to a single element. If and when you try to access elements 2-5, you'll get either meaningless garbage or a segmentation fault for trying to access memory you don't own. Even worse, the variable i is allocated on the stack, so when the function change_it exists, the function's data will be popped off the stack, and trying to access the address of i will yield either garbage or a segmentation fault for trying to access memory you don't own. See a pattern?
I'm not really sure how to correct this code, as I'm not sure what you were trying to accomplish, but correcting the aforementioned errors, your code now looks something like this:
#include <stdio.h>
void change_it(int arr[]);
int main()
{
int a[5];
int *p = a; // Equivalent to int *p = &a[0];
printf("a address: %p\n", a); // Should be equal to p
printf("p address: %p\n", p); // Should be equal to a
a[0] = 1;
printf("a[0] = %d\n", a[0]); // 1
printf("p has the value %d\n", *p); // 1
change_it(a);
p = a;
printf("a address: %p\n", a);
printf("p address: %p\n", p);
printf("a[0] = %d\n", a[0]);
printf("p has the value %d \n", *p);
return 0;
}
void change_it(int arr[])
{
int i=777;
arr[0] = i;
// Could be just:
// arr[0] = 777;
}
Output:
p address: 0x7fffc951e0b0
a[0] = 1
p has the value 1
a address: 0x7fffc951e0b0
p address: 0x7fffc951e0b0
a[0] = 777
p has the value 777
Note: Your memory address can and probably will be different from these, all it matters is that p and a are equal in both.
Anyways, hope this helps. Let me know if you have any questions.
Alright, you I believe do not have basic understanding of a function: First lets start with declaration and definition:
void change_it(int[]); // THIS IS DECLARATION
int main ()
{
void change_it(int[]); // THIS IS DECLARATION (duplicate and unnecessary
....
}
void change_it(int[] a) // THIS IS DEFINITION
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
declaration of the function only needs (you can put parameter name for readability) a parameter type, where as definition has to have name of the parameter because in definition parameters are local variables.
printf("p has the value %u \n",(int)p);
This will print the address of p not the value of p. So this should be
printf("p has the value %u \n", *p);
And finally we get to the body of a function. Where you are depending on somthing that have been locally assigned and putting it back into parameters
void change_it(int[] a)
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
so q is pointer and you are assigning address of local variable i to it. Well what happens when your program exists the function? i might disappear thus loosing its values and its address, which is assigned to q which means q is loosing its variable and value, and which is assigned to a which might loos its variable because it is pointing to i in your function.
This part here:
int a[5],*p=1;
void change_it(int[]); // Here, doesn't compile
printf("p has the value %u \n",(int)p);
That statement isn't just valid, as far as I know, you can't declare a function inside another function in C.
Also:
void change_it(int[]) // Here, an error
{
int i = 777, *q = &i;
a = q;
}
This function needs an argument, but you supplied only its type (being int[]),
void change_it(int a[]) fixes the problem
Your program does not compile and produce warnings. It would not work as you intended.
1) p is a pointer. To access value which it points to you have to dereference it using * dereference opearator.
2)
void change_it(int[]);
is not needed in the body of main.
3)
the invocation of change_it() seems to have no effect
If you want to change a[0] element inside the function change_it name the passing parameter to a and dereference the q pointer,
The working program may look as this:
#include <stdio.h>
void change_it(int a[]);
int main()
{
int a[5] = {0}; // init all element of `a` to `0`
int *p; // declare int pointer
p = a; // p point to array `a`
// print the first element of array `a`
printf("a[0] has the value %d \n",(int)*p);
// call function change_it, pass `a` as the argument
change_it(a);
printf("a[0] has the value %d \n",(int)*p);
return 0;
}
// change the value of the first element of array `a` to 777
void change_it(int a[]) {
int i=777, *q; // declare int i and pointer
q = &i; // pointer `q` points to the `i` now
a[0] = *q; // a[0] is assigned value = 777;
}
Output:
a[0] has the value 0
a[0] has the value 777

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.

Behavior of call by reference

In my program, I am a passing a pointer to a function. In that function, I am making the passed pointer to point to a location what another pointer points. When returned from function it no longer points to its new location, instead it points to its original location. As I am passing by call by reference, it should point to its new location. Why is this happening?
// a program to show behavior of call by reference
#include <stdio.h>
#include <stdlib.h>
void ptrAllocation(int *p)
{
int k = 10 ;
int *t = &k;
p = t ;
printf("\np now points : %d",*p);
}
int main()
{
int i = 5 ;
int *a = &i;
ptrAllocation(a);
printf("\na now points : %d",*a);
}
Output:
p now points : 10
a now points : 5
I know the problem can be solved if I make a function like:
void ptrAllocation(int **p)
{
int k = 10 ;
int *t = &k;
*p = t ;
printf("\np now points : %d",**p);
}
But I am not getting the clear picture of what is happening exactly in the program from the point of view of pointers, location, stack?
MY PROBLEM:
Is that the pointer k points to whatever pointer t points in the function ptrAllocation, but as the function returns, there no longer exists pointer t, hence pointer p points to its original location.
Is it not the case that when assigning a pointer to a pointer like in p = t, both pointers p and k point to the same location and not that p points to t and t points to the location.
Please describe how the stack and the pointers work in the program above.
You are passing by value, not by reference. What you pass by value is a pointer, but the pointer is still passed by value. You can change what it points at; you can't change the pointer in the calling function. If you wanted to do that, you'd have to pass a pointer to the pointer, as in your second code fragment.
Here's a derivative program based on your code, and its output from a 64-bit build on Mac OS X 10.8.3. I used 12 in the address printing to give uniform width pointer output on this machine; you can tune it to suit your machine.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
static int q = 42;
static void ptrAllocation(int *p, int **z)
{
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
int k = 10;
int *t = &k;
*z = &q;
p = t;
printf("After:\n");
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
}
int main(void)
{
int i = 5;
int j = 7;
int *a = &i;
int *b = &j;
printf("Before:\n");
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
ptrAllocation(a, &b);
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
}
Sample output:
Before:
a now points at: 5 (0x7FFF59E1852C)
b now points at: 7 (0x7FFF59E18530)
p now points at: 5 (0x7FFF59E1852C)
z now points at: 7 (0x7FFF59E18530) (0x7FFF59E18538)
After:
p now points at: 10 (0x7FFF59E18534)
z now points at: 42 (0x000105DE8050) (0x7FFF59E18538)
a now points at: 5 (0x7FFF59E1852C)
b now points at: 42 (0x000105DE8050)
Studying the output should help you understand better what is going on. You can print more address values if you need to.
Please describe how the stack and pointers work in the program above.
I'll discuss the program I showed because the addresses are available for discussion.
The variable q is located at address 0x000105DEE8050. Inside main(), variable i is stored on the stack at memory location 0x7FFF59E1852C; the variable j is stored at memory location 0x7FFF59E18530. The variable a contains the address of i; b contains the address of j; the address of b itself is 0x7FFF59E18538; the address of a is not shown in the output.
When ptrAllocation() is called, the value of a is pushed onto the stack, and the address of b is also pushed onto the stack. It is an implementation detail which order the values are pushed.
Inside ptrAllocation(), the variable p contains a copy of the value in a in the main() function. The variable z contains the address of b in the main() function. The variable k is on the stack; the variable t contains the address of k.
The assignment *z = &q; assigns the address of q to the pointer b via the argument z; it changes what b points at by changing the value of b in the calling function — which is only possible because the address of b was passed.
The assignment p = t; changes the local variable p (which contains a copy of what is in the variable a in main()) so that it points to what t points at, which is k. Therefore, the 'After' print statements note that p points at the value 10. The value that **z points at is in q and is still 42; *z is the address of q.
On return, a in the main() code is unchanged because its address was not passed to ptrAllocation(), but b is changed because its address was passed to ptrAllocation() and ptrAllocation() modified the pointer.
As noted in the comments to the question, your second implementation of ptrAllocation() is flawed too:
void ptrAllocation(int **p)
{
int k = 10 ;
int *t = &k;
*p = t ;
printf("\np now points : %d",**p);
}
After calling this function, the pointer passed to it cannot reliably be dereferenced because *p points to a local variable which ceases to be valid once ptrAllocation() returns. You could fix this issue by making k into static int k = 10;, or by arranging for *p to point to some other int value that has a scope outside the function — a variable defined outside the function, or a dynamically allocated variable:
void ptrAllocation(int **p)
{
static int k = 10;
int *t = &k;
*p = t ;
printf("p now points : %d\n", **p);
}
Or:
void ptrAllocation(int **p)
{
*p = malloc(sizeof(*t));
if (*p != 0)
{
**p = 10;
printf("p now points : %d\n", **p);
}
}
Note, incidentally, how the code I've left has the newlines at the end of each printf() statement. Get into the habit of placing newlines at the end of lines of output. If you don't, you don't know when the output will appear (because it may be held up until the next time a newline is generated).
You are changing the pointer in function and not in the main code. Therefore only the copy will be changed. In the later case you change the location of pointer so the value at that address is changed. Take it like variables, when you change the copy, nothing happens to the original but when you change the location, the variable is changed. So you have to pass the address of pointer to change it.
The C language only implements call by value. Call by reference refers to passing (by value) a pointer p, and then using *p to manipulate what it points at (references).
If you want a function to change a pointer, you have to reference the pointer, such as by forming a pointer to pointer, and pass the reference to the function using call by value. The terms "reference" and "pointer" may be used nearly interchangeably in C — referencing is just what a pointer does.
In C++ call by reference is a language feature, but in C it's an idiom.

Resources