I am having some problems with double pointers as arguments in C.
From what I know so far:
when I have a function that takes a pointer as an argument, say a function called functionX(int *y)
then when I call functionX, let's say by: functionX(&randomvar),where randomvar is an integer containing a certain value (let's say 5), then C will create a pointer that is also called 'randomvar' that contains the address of randomvar. So the output of *randomvar will be 5.
Is my understanding correct?
If so, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the address of randomvar, another that contains the address of the first pointer.
I'm a bit stumped here I'm not sure if it's correct.
From what I know so far: when I have a function that takes a pointer
as argument, says a function called functionX(int *y) then when I
call functionX, let's say by: functionX(&randomvar),where
randomvar is an integer containing a certain value (let's say 5),
then C will create a pointer that is also called 'randomvar' that
contains the addresse of randomvar. So the ouput of *randomvar
will be 5.
Is my understanding correct?
No.
The situation you describe would be along these lines:
void functionX(int *y) {
// ...
}
int main(void) {
int randomvar = 5;
functionX(&randomvar);
}
The expression &randomvar in the main() function of that code does evaluate to the address of that function's local variable randomvar. The expression has type int *, the same as parameter y to function functionX(), so it is well suited for use as an argument to that function. All well and good so far.
But the expression &randomvar designates only a value, not an object. There is no storage reserved for it, and therefore it does not have an address. It also has no name, and in particular, it is not named 'randomvar'. Inside function functionX(), (a copy of) that value can be accessed as y, and the expression *y will evaluate to 5. Nowhere in the code presented is *randomvar a semantically valid expression.
If so
It is not so.
, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
Not at all. &randomvar is a single expression. Evaluating it produces one value, which, as I've already covered, has type int *. This is does not match a function parameter of type int **. An int ** is a pointer to an int *. To obtain one, you might take the address of an object (not a value) of type int *:
void functionY(int **z) {
// ...
}
int main(void) {
int randomvar = 5;
int *varptr = &randomvar;
functionY(&varptr);
}
When done that way, there are indeed two pointers, one an int * and the other an int **, but the former needs to be declared explicitly.
Visualize it this way:
void foo(int a);
void bar(int *b);
void baz(int **c);
// main function
{
int x = 5;
int *p = &x;
foo(x);
bar(p);
baz(&p);
}
// **main** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
ABCD:4000 x 5
ABCD:4008 p ABCD:4000
// **foo** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:2000 a 5
// a new variable is created.
// any changes made on 'a' will not affect 'x' in 'main'
// **bar** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:4000 b ABCD:4000
// a new pointer is created pointing to 'x'
// 'b' points to 'x' and '*b' means 'the value stored in ABCD:4000'
// any changes made on '*b' will affect 'x' in main
// **baz** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:8000 c ABCD:4008
// a new pointer is created pointing to 'p'
// 'c' points to 'p' and '*c' means 'the value stored in ABCD:4008'
// any changes made on '*c' will change the value of 'p' in main
// if '**c = 7' is executed, x will be assigned '7'
// if '*c = ABCD:8000' is executed, p will no longer point to 'x'
hen when I call functionX, let's say by: functionX(&randomvar),where
randomvar is an integer containing a certain value (let's say 5), then
C will create a pointer that is also called 'randomvar' that contains
the addresse of randomvar
The name of the pointer in the function functionX is y because you wrote yourself that it is the name of the function parameter functionX(int *y).
If so, then when the function has double pointers : functionX(int **y)
and by doing functionX(&randomvar) creates 2 pointers, one that
contains the adresse of randomvar, another that contains the adresse
of the first pointer. If you have a function declared for example like
The operator & creates one pointer not two pointers.
If you have a function declared for example like
void functionX(int **y);
and a variable declared like
int randomvar = 5;
then such a call of the function like
functionX( &randomvar );
generates a compilation error because the type of the argument is int * while the type of the parameter according to the function declaration is int **.
You may not write for example like
functionX( &&randomvar );
because using the first operator & creates a temporary object of the type int *. And you may not apply the operator & to a temporary object.
To call the function you could write
int *p = &randomvar;
functionX( &p );
In this case the type of the argument will be int ** as it is required by the parameter type.
Here is a demonstrative program.
#include <stdio.h>
void f( int *p )
{
printf( "The value of p is %p\n"
"the pointed value is %d\n",
( void * )p, *p );
}
void g( int **p )
{
printf( "The value of p is %p\n"
"the pointed value is also a pointer %p\n"
"the pointed value by the dereferenced pointer is %d\n",
( void * )p, ( void * )*p, **p );
}
int main(void)
{
int x = 5;
f( &x );
putchar( '\n' );
int *p = &x;
g( &p );
return 0;
}
Its output might look for example like
The value of p is 0x7ffced55005c
the pointed value is 5
The value of p is 0x7ffced550060
the pointed value is also a pointer 0x7ffced55005c
the pointed value by the dereferenced pointer is 5
You can just keep chaining pointers forever if you like. Here's some code that demonstrates this:
#include<stdio.h>
void foo(int ***A, int **B, int *C) {
printf(" %p A\n %p *A\n %p **A\n %d ***A\n", A, *A, **A, ***A);
printf(" %p B\n %p *B\n %d **B\n", B, *B, **B);
printf(" %p C\n %d *C\n ", C, *C);
}
int main(void) {
int D = 8;
int* C = &D;
int** B = &C;
int*** A = &B;
foo (A,B,C);
printf("%p &D (in main)\n", &D);
return 0;
This will give results like this for the dereferenced pointers, each '*' comes off just as it goes on, so notice how **A = *B = C = &D
0x7ffc81b06210 A
0x7ffc81b06218 *A
0x7ffc81b06224 **A
8 ***A
0x7ffc81b06218 B
0x7ffc81b06224 *B
8 **B
0x7ffc81b06224 C
8 *C
0x7ffc81b06224 &D (in main)
Note finally that the call foo (&B, &C, &D) will produce the same result.
There is no pointer made of the same name as the passed variable when invoking a function with an address of a passed variable as argument. It simply passes the address of a certain variable when preceded by the & operator. Inside the called function the pointer which holds this address can have any valid identifier.
when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
You cannot pass the address of an int object, which is of type int*, when the function expects an object of type int**.
Speaking for passing double pointers in general, the concept is the same as said above.
No, your understanding is not correct. C doesn't "create" anything in the sense you assumed -- most variables are simply labels of memory locations (not only though, they may "alias", or label, CPU registers) -- your randomvar in the scope where functionX is called is a label of a memory area allocated to store an integer and which is interpreted as integer. The value of &randomvar unary expression (operator & with a single operand randomvar) is the address of the data. That address is what is passed to functionX as y, meaning that a memory location (or CPU register) is reserved and stores the address (not the value) of randomvar.
As an example, say your program declares a variable like int randomvar; -- when executed, a part of RAM -- 4 bytes for an int typically -- is reserved to hold the variable value of randomvar. The address isn't known until the program is executing in memory, but for the sake of the example let's imagine the address 0xCAFEBABEDEADBEEF (8 bytes) is the one that points to the 4 bytes to hold the integer value. Before the variable is assigned a value, the value at the address is indeterminate -- a declaration of a variable only reserves the space to hold the value, it doesn't write anything at the address, so before you assign a value to the variable, you shouldn't even be using the value at all (and most C compilers can warn you about this).
Now, when the address is passed to functionX this means that for the function, label y is 8 bytes reserved at some memory location, to store an address of an integer variable. When called like functionX(&randomvar), y stores 0xCAFEBABEDEADBEEF. However, y also [typically] has an address -- the former value (address of randomvar) has to be stored somewhere! Unless a CPU register stores the value, in which case there is no [RAM] address, naturally.
For a pointer to a pointer like int * * y, y labels a memory location reserved to store an address to an address of an integer variable.
Related
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
I am doing a homework of C programming.
#include <stdio.h>
typedef struct JustArray {
char *x;
} JustArray;
int main()
{
JustArray Items[12];
char *d = "Test";
Items[0].x = (char *) &d;
printf("Pointer: %p\n", &d);
printf("Address: %u\n",&d);
printf("Value: %s\n", d);
/*------------------------------------*/
//Knowing address of d from above, print value stored in it using Items[0].x. Cannot use &d, *d, or d.
char *ptr;
ptr = Items[0].x;
printf("%p\n", Items[0].x);
printf("%p\n", &ptr);
printf("%s\n", ptr);
return 0;
}
The output of ptr needs to be "Test" as well but it is showing me weird characters. The assignment is to have find a way to use the address info in Items[0].x and print its value "Test" in console. I could not find a way to do it...
Remember that the value of a pointer is an address. The content of a pointer (i.e. its dereference, the value pointed, addressed by it) is a value (with the type being pointed) which is in another place. So a int* has as value an address of another variable (of type int) which is stored in another address. Note that each primitive variable in C is the name of a data stored in some address.
int p = 1;
p above is a var of type int. It has 1 as value, which is directly given by p (so p == 1). p has an address (say 0x11111) that can be accessed with &p (so &p == 0x11111). Thus, p is the name of a variable whose value is an int (1) and whose address is 0x11111 (given by &p). This means that the value 1 (which is an int) is stored in the address 0x11111.
int* q = 0x22222;
q above is a var of type int* (pointer to int, meaning "an address to a var of type int"). q has an address as value (in this case is 0x22222), which is directly given by q (so q == 0x22222). but q also has an address (say 0x33333), which can be accessed with &q (so &q == 0x33333). Thus, q is the name of a variable whose value is an address to int (0x22222, given by q) and whose address is 0x33333 (given by &q). Basically, the value 0x22222 (which is an address) is stored in the address 0x33333.
You can use the prefix operator * over q to dereference it, i.e. access its content, which is the value stored in the address 0x22222, which is the value of q. So basically we have: q==0x22222, &q==0x33333, and *q==[whatever is the value stored in the adress 0x22222]. Now consider this:
int* r = &p;
Remember that p has value 1 (an int given by p itself) and address 0x11111 (given by &p). Now I declared a pointer to int called r and initialized it with the address of p (0x11111). Thus, r is a pointer whose value is an adress (0x11111), but it also has an address (say 0x44444).
The operator * prefixing a pointer lets us access the value of the address that is its value. So *r will give us 1 because 1 is the value stored in the address 0x11111, which is the value of r and the address of p at the same time. So r==&p (0x11111==0x11111) and *r==p (1==1).
Now lets go back to your code. When you declare a char* you already have a pointer, so the printing of it will be an address if you set %p as the desired format or a string if you set %s as the desired format. (The %s makes the function printf iterate throughout the contents whose start address is the value of the given pointer (and it stops when it reaches a '\0'). I fixed your code (and modified it a little bit for the sake of readability). The problem was that you were sending the addresses of the pointers instead of the pointers themselves to the function printf.
#include <stdio.h>
typedef struct justArray
{
char* x;
}
JustArray;
int main()
{
//d is a pointer whose content is an address, not a char 'T'
char* d = "Test";
printf("Pointer: %p\n", d); //print the address (no need for &)
printf("Address: %lu\n", (long unsigned) d); //print the address again as long unsigned)
printf("Value: %s\n", d); //print a string because of the %s
JustArray Items[12];
Items[0].x = d;
printf("%p\n", Items[0].x); //Items[0].x == d, so it prints the same address
char* ptr = Items[0].x;
printf("%p\n", ptr); //ptr == Items[0].x, so it prints again the same address
printf("%s\n", ptr); //prints the string now because of the %s
return 0;
}
The output of this program will be:
Pointer: 0x400734
Address: 4196148
Value: Test
0x400734
0x400734
Test
The key here is to notice what this line does:
Items[0].x = (char *) &d;
Observe first that d is a char * (i.e. a null-terminated string in this case), thus &d (taking a reference to it) must yield a value of type char * * (i.e. a pointer to a pointer to a char, or a pointer to a string). The cast to char * has to be done for the C type checker to accept the code. [Note that this is considered very bad practice, since you are forcing a value of one type into a value of another type that makes no sense. It's just an exercise though, and it's precisely this "bad practice" that makes it a bit of a challenge, so let's ignore that for now.]
Now, to get back d again, given just Items[0].x, we need to sort of "invert" the operations of the above line of code. We must first convert Items[0].x to its meaningful type, char * *, then dereference the result once to get a value of type char * (i.e. a null-terminated string).
char *d_again = *((char * *) Items[0].x);
printf("%s\n", d_again);
And viola!
This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 9 years ago.
I dont understand what this means. If I were to try and guess I'd say byValue argument passing is when you pass an argument based on the value of an variable, so I'm thinking:
if (a == 1){
PassAnArgumentOrSomething()
}
However that is probably wrong :/
As for byReference, I have no idea.
If anyone can help me out that be awesome of you :)
With the exception of arrays and functions (see below), C always passes arguments `by value': a copy of the value of each argument is passed to the function; the function cannot modify the actual argument passed to it:
void foo(int j) {
j = 0; /* modifies the copy of the argument received by the function */
}
int main(void) {
int k=10;
foo(k);
/* k still equals 10 */
}
If you do want a function to modify its argument you can obtain the desired effect using pointer arguments instead:
void foo(int *j) {
*j = 0;
}
int main(void) {
int k=10;
foo(&k);
/* k now equals 0 */
}
This is sometimes known as `pass by reference' in other languages.
There is no pass by reference in c language
Passing by value: means that you are creating a temporary copy of the variable and sending to the parameter.
Passing by reference(no such concept in c language): means that you are just giving another name to the original variable while calling and no temporary copy of the variable is being created.
Calling by value:
int foo(int temp)
{
/.../
}
int main()
{
int x;
foo(x); /* here a temporary copy of the 'x' is created and sent to the foo function.*/
}
Calling by reference(no such concept in c language)
int foo(int& temp)
{
/.../
}
int main()
{
int x;
foo(x); /* here no temporary copy of 'x' is being created rather the variable *temp* in the calling function is just another name of the variable a in the main function*/
}
Passing an argument by value means you are passing a copy:
void f(int x)
{
x = 7;
// x is 7 here, but we only changed our local copy
}
void g()
{
int y = 3;
f(y);
// y is still 3 here!
}
Passing an argument by reference means you are not passing a copy, but instead passing some way of referencing the original variable. In C, all arguments are pass by value, but what is typically done to get the same effect as passing by reference is to pass a pointer:
void f(int *x_ptr) { *x_ptr = 7; }
void g()
{
int y = 3;
f(&y);
// y is 7 here
}
Arrays are passed in such a way that it appears similar to pass-by-reference, however what is actually happening is more complicated. For example:
void f(int a[]) { a[0] = 7; }
void g()
{
int b[3] = {1,2,3};
f(b);
// b[0] is 7 here! looks like it was passed by reference.
}
What is actually happening here is that the array b is implicitly converted to a pointer to the first element (this is known as decay). The int a[] notation for the parameter to f is actually syntactic sugar for a pointer. The above code is equivalent to:
void f(int *a) { a[0] = 7; }
void g()
{
int b[3] = {1,2,3};
f(&b[0]);
// b[0] is 7 here
}
Passing by value is passing the value itself; it makes a copy of the value, and any changes you make in the new function are NOT saved to the original variable:
void foo(int num)
{
num = 5; // Does not save to the original variable that was passed when foo was called
...
}
Passing by reference is passing the location of the variable; it allows the new function to directly edit the original variable:
void bar(int * num)
{
*num = 5; // Changes the variable in the original function
...
}
in-depth explanation
whenever a program loads, it gets a memory area so called address space which gets divided into various regions
code/text : contains the statements of program (collections of statements).
global : contains the global variable if any.
constant : used for constant or literal storage.
heap : used for dynamic memory need.
stack : function used its for variable.
consider a function so defined as
void doSomething(int x)
{
x++;
}//end of function
is called as doSomething(5) or doSomething(y) in another function or main function .
here
x is local variable to function "doSomething". It gets its home (memory location) somewhere in stack region.
When doSomething(5) is called 5 gets copied to x's memory or doSomething(y) is called value/content of y (different memory location) gets copied to x's memory. Whatever operations applied on x, will not affect y 's content/value at all. Since its memory location is different.
Whenever execution flow reachs at end of function x dies/gets destroyed. Whatever value of x is not accessible/available. In short, update is lost and y is unaffected (Change is not reflected).
This is what so called Call by Value
Now
Consider an another function so defined as
void doSomething(int *x)
{
(*x)++;
}
is called as doSomething(&y)
here x is called pointer (conceptually called reference*).It will also gets home somewhere in stack region
When doSomething(&y) is called address of y gets copied to x's location block. Since this x is special variable so called pointer that holds address and it is said that x refers/points to y.
When (*x)++ is applied, here * is indirection operator which will bring whom x refer to the context ie. (*x)++ will indirectly change the value of y by 1. Nothing will happen to x's value itself.
Whenever execution flow reach at end of function *x dies/gets destroyed as expected but this time change is made to y (indirectly) which is still alive somewhere in stack region (change is reflected).
Also not that this time doSomething(&5) or doSomething(any literal) is not possible because it's illegal to get address of any literal.
This is what so called Call by Reference/Call by Pointer.
note that Call by Reference has another meaning in C++ but conceptually remains same.
Let's look at the "calling" of functions first.
In C, the arguments to a function are typically "by value". Below, after calling sqrt(x), the value x is not changed for sqrt() received a copy of the value x, thus never gaining an ability to affect x.
y = sqrt(x);
// x did not change
printf("%f is the square root of %f\n", y, x);
Array parameters to a function appear to be "by reference". After fgets() is called, buf is expected to be altered. fgets() did not receive a copy of, but a "reference" to the char array. Thus fgets() could affect the contents of the array.
char buf[80] = { 0 }; // array 80 of char
printf("Before <%s>\n", buf); // "<>"
fgets(buf, sizeof buf, stdin);
printf("After <%s>\n", buf); // "<Hello World!>"
Let's now look at the "receiving" part: the function.
Function parameters of type double, int, struct types are received by value. The value of f here is the copy of the x above. Any changes made to f do not affect the x in the calling code.
double sqrt(double f) {
double y;
... // lots of code
return y;
}
Now comes the tricky bit and this is where there is lots of discussion in C.
The parameter s in fgets() below was not assigned the buf above (array 80 of char), instead s was assigned the pointer type derived from buf: address of the first element of an buf. By knowing the address of the array elements of buf (via s), fgets() affects what was printed above.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// code
s[i] = ThisAndThat();
// code
return s;
}
Let's now see how fgets() otherwise might be called:
char *p = malloc(80);
*p = '\0';
printf("Before <%s>\n", p); // "<>"
fgets(p, 80, stdin);
printf("After <%s>\n", p); // "<Hello World!>"
In this 2nd example, p is a "pointer to char". It is passed by value to fgets(). fgets() received, via s, a copy of p.
The central idea: fgets() does not know if it received an "address of the first element of an array" or a copy of a "pointer to char". In both cases, it treats s as a "pointer to char".
Let's assume fgets() did the following. Before s being changed, it affects the data pointed to by s. Then s, the pointer, changed. s is a local variable and this assignment does not change the calling routines variables buf nor p.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// lots of code
s[0] = '\0';
// more code
s = NULL;
return s;
}
Note: There are other issues such as passing functions as parameters and encapsulating arrays in structures to consider.
I found the following code in my textbook:
#include<stdio.h>
void disp( int *k)
{
printf("%d",*k);
}
int main( )
{
int i ;
int marks[ ] = { 55, 65, 75, 56, 78, 78, 90 } ;
for ( i = 0 ; i <= 6 ; i++ )
disp ( &marks[i] ) ;
return 0;
}
}
The code works just fine, but I have doubts regarding the logic:
I am sending the address of variables of the array. But in the disp function I am using a pointer variable as the argument and printing the value of the pointer. So the type of argument sent from the main function should mismatch with the argument of disp. So how does it work?
I tried to do the same by changing the disp function as
void disp( int (&k))
{
printf("%d",*k);
}
but I am getting an error. What should I do to make it work by taking an address as an argument, i.e. void disp(int &k)?
1) I am sending the address of variables of the array. But in the disp function I am using a pointer variable as argument and printing the value of the pointer.
Understand that a pointer is an address. So &marks[i] is an int*. And you're not printing the value of the pointer, but the value it points to.
printf("%d",*k);
the *k dereferences the pointer and gives the pointed-to value.
void disp( int (&k))
is invalid syntax in C, &k is not a valid identifier.
When you do: -
int *k = &marks[i];
The above statement is broken into: -
int *k; -> Integer Pointer
k = &marks[i]; --> `k` points to the address of marks[i]
So, basically, k is the an integer pointer, that points to the address of the current element in your array.
So, when you print *k, it is equivalent to: - *(&marks[i]), which dereferences the value and prints the element marks[i].
So, in the below code, you can understand, how the whole process of pointer assignment and de-referencing takes place: -
int *k; // Declaring integer pointer.
// Actually 'k' is equal to the `&marks[i]`.
// '*k' is just the indication of it being a pointer
k = &marks[i];
// Dereference pointer
*k = *(&marks[i]); --> = marks[i]
printf("%d",*k); --> printf("%d",marks[i]);
Also, since you cannot declare variable like: -
int &k = &marks[i];
You cannot have them as parameter in your function: -
void disp(int &k);
Because, eventually the address of array element passed is stored in this variable. So, it has to be int *k.
1) You understand correct that in the for loop the address is sent to disp. But disp receives pointer as an argument... which is just an address. Inside that function you don't print the "value" of the pointer. You print the value pointed by that pointer (the value that is on that address). In the printf call "*k" you dereference the pointer - get the value pointed by that pointer.
2) You didn't change the function so that it receives address. You changed it so that it receives reference. You can also say it receives a hidden pointer - it does the same as the pointer but you don't need to "*k" to dereference it - you use it as a normal variable
Read up on pointers and address-of variable. And how they're used.
When a function expects a pointer, you HAVE to send either a pointer or an address of a variable. Since pointers hold addresses.
The second problem you're facing is that of syntax error. Because there is no & operator that can be applied to "lvalues".
Well, simply i can say that you are passing an address in the function and recieving it in a pointer..Its correct as pointer can point to or hold the address. Or other way simply if you send an address but store it in a reference variable but the reference of whom, is the question to be asked. Try vice versa you'll understand the structure more better...
" Double pointers are also sometimes employed to pass pointers to functions by reference "
can somebody can explain me the above statement, what exactly does point to function by reference means ?
I believe this example makes it clearer :
//Double pointer is taken as argument
void allocate(int** p, int n)
{
//Change the value of *p, this modification is available outside the function
*p = (int*)malloc(sizeof(int) * n);
}
int main()
{
int* p = NULL;
//Pass the address of the pointer
allocate(&p,1);
//The pointer has been modified to point to proper memory location
//Hence this statement will work
*p=10;
//Free the memory allocated
free(p);
return 0;
}
It means that you have a function that takes a pointer pointer (type int ** for example). This allows you to modify the pointer (what data it is pointing to) much in the way passing a pointer by reference would allow.
void change (int *p) {*p = 7;}
void Really_Change (int **pp) {*pp = null;}
int p = 1;
int *pp = &p;
// now, pp is pointing to p. Let's say it has address 0x10;
// this makes a copy of the address of p. The value of &p is still 0x10 (points to p).
// but, it uses that address to change p to 7.
change(&p);
printf("%d\n", p); // prints 7;
// this call gets the address of pp. It can change pp's value
// much like p was changed above.
Really_Change(&pp);
// pp has been set to null, much like p was set to 7.
printf("%d\n", *pp); // error dereference null. Ka-BOOM!!!
So, in the same way that you can pass a pointer to an int and change the value, you can pass a pointer to a pointer and change its value (which changes what it points to.)
I'll try to explain with both code and plain english :). The explanation may get long, but it will be worth the while.
Suppose we have a program, running its main() function, and we make a call to another function that takes an int parameter.
Conceptually, When you pass a variable as a parameter to a function, you can do so in (roughly speaking) two ways: by value, or by reference.
"By value" means giving the function a copy of your variable. The function will receive its "content" (value), but it won't be able to change the actual variable outside its own body of code, because it was only given a copy.
"By reference", on the other hand, means giving the function the actual memory address of our variable. Using that, the function can find out the variable's value, but it can also go to that specified address and modify the variable's content.
In our C program, "by value" means passing a copy of the int (just taking int as argument), and "by reference" means passing a pointer to it.
Let's see a small code example:
void foo(int n) {
n = 10;
printf("%d\n", n);
}
int main() {
int n = 5;
foo(n);
printf("%d\n", n);
return 0;
}
What will the output of this program be? 10 10? Nope. 10 5! Because we passed a copy of the int, by value and not by reference, foo() only modified the number stored in its copy, unable to reach main()'s copy.
Now, if we do it this way:
void foo(int* n) {
*n = 10;
printf("%d\n", *n);
}
int main() {
int n = 5;
foo(&n);
printf("%d\n", n);
return 0;
}
This time we gave foo() our integer by reference: it's actual memory address. foo() has full power to modify it by accessing it's position in memory, foo() and main() are working with the same copy, and so the output will be 10 10.
As you see, a pointer is a referece,... but also a numerical position in memory. It's similar to an int, only the number contained inside is interpreted differently. Think of it this way: when we pass our int by reference, we're passing an int pointer by value!. So the same by value/by reference logic can be applied to pointers, even though they already are references.
If our actual variable was not an int, but an int reference (pointer), and we wanted main() and foo() to share the same copy of that reference so that foo() can modifiy it, what would we do? Why of course, we'd need a reference to our reference! A pointer to a pointer. That is:
int n; /* integer */
int* n; /* integer reference(pointer). Stores an int's position in memory */
int** n; /* reference to integer reference, or double pointer.
Stores int*'s memory address so we can pass int*s by reference. */
I hope this was useful.