Why sometimes pass pointer of pointer as parameters? [duplicate] - c

This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 2 years ago.
I'm new to C, sorry if my question sound dumb.
I see some function takes a "double" pointer as parameter, for example:
int main(int argc, char **argv)
{
...
}
I can understand the need for a double pointer such as argv, since argv is the pointer to the first element of argument array whose element is also a pointer to a char type. double pointer is needed in this case.
But for some functions like:
int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);
I don't understand why a double point is needed, since there is no array element involved, and I think getaddrinfo calls malloc internally, so it might be a reason to use double pointer, but we can have sth like this:
int main()
{
char *ptr_main;
test(ptr_main);
free(ptr_main);
}
void test(char *ptr)
{
ptr = malloc(10);
}
so the parameter is a single pointer char * ptr, no char **ptr is needed?

Passing a pointer, or address of an object allows the value stored at that location in memory to be changed by the function, so when the function returns, the information stored at that address now contains updated values. Likewise if a function argument accepts a pointer variable, and the pointer variable is to be changed, the address to that pointer must be passed, thus requiring the function prototype to be a pointer-to-pointer.
Addressing your question may illustrate: getaddrinfo question: I don't understand why a double point is needed, since there is no array element involved
Usage for this struct is typically:
struct addrinfo *result;//pointer variable
getaddrinfo("hostname", "servicename", NULL, &result);
// |_Passing address of a pointer variable.
// thus requiring prototype to accommodate
So as explained, for the function to receive updated struct information, it needs to send the address of the pointer variable, requiring it to be a double pointer:
int getaddrinfo(const char *host, ..., struct addrinfo **result);

Your code is incorrect. ptr is local to the scope of test. A pointer is just a number representing a memory address. You probably wouldn't expect test in the following code to affect the value of number_main, right?
int main()
{
int number_main;
test(number_main);
printf("%d\n", number_main);
}
void test(int number_main)
{
number_main = 10;
}
Maybe it helps if you internalize char * as some fictional type you'll call number_that_represents_memory_address, which you then think about as no different than int in this case?

This function
void test(char *ptr)
{
ptr = malloc(10);
}
that shall be declared before its usage in main deals with a copy of the value of the passed argument in main
char *ptr_main;
test(ptr_main);
You can imagine the function call and the function definition the following way
char *ptr_main;
test(ptr_main);
//...
void test( /* char *ptr */ )
{
char *ptr = ptr_main;
ptr = malloc(10);
}
So as you can see within the function it is the local variable ptr that is changed. The argument ptr_main that was not initialized in main and has indeterminate value stays unchanged.
To change the original pointer ptr_main you have to pass it to the function by reference.
In C the mechanism of passing by reference is implemented by passing an object indirectly through a pointer to it.
From the C Standard (6.2.5 Types)
— A pointer type may be derived from a function type or an object
type, called the referenced type. A pointer type describes an object
whose value provides a reference to an entity of the referenced
type. A pointer type derived from the referenced type T is sometimes
called ‘‘pointer to T’’. The construction of a pointer type from a
referenced type is called ‘‘pointer type derivation’’. A pointer type
is a complete object type.
So the function definition should look like
void test( char **ptr )
{
*ptr = malloc(10);
}
And called like
test( &ptr_main );
Thus dereferencing the pointer ptr in the function we get a direct access to the pointed object (pointer) ptr_main and it is the pointed (referenced) object that is changed now in the function
To make it more clear consider the following demonstrative program.
#include <stdio.h>
#include <stdlib.h>
void f1( int *px )
{
*px = 10;
}
void f2( int **ppx )
{
*ppx = malloc( sizeof( int ) );
**ppx = 20;
}
int main(void)
{
int x = 0;
printf( "Before calling f1 x = %d\n", x );
f1( &x );
printf( "After calling f1 x = %d\n", x );
int *px = &x;
printf( "Before calling f2 px = %p and *px = %d\n", ( void * )px, *px );
f2( &px );
printf( "After calling f2 px = %p and *px = %d\n", ( void * )px, *px );
free( px );
return 0;
}
The program output might look like
Before calling f1 x = 0
After calling f1 x = 10
Before calling f2 px = 0x7ffe79dd572c and *px = 10
After calling f2 px = 0x55db88f5d270 and *px = 20
To change the object x declared in main in the function f1 we need to pass it to the function by reference. Otherwise the function will deal with a copy of the value of the object.
The same situation takes place with the pointer px. Pointers are objects. If we want to change the pointer px declared in main in the function f2 we need to pass it to the function by reference. Otherwise the function will deal with a copy of the value of the object.
And as you can see from the program output the function f2 indeed changed the value of the pointer px declared in main.

Related

How to understand secondary pointer?

i want to ask a question about pointer:
void fun(const char** a) {...}
1.
const char* b = nullptr;
fun(&b);
2.
const char** b = nullptr;
fun(b);
why use 1 but not 2?
1 is good, 2 donnot work
C uses pass by value for function call arguments. That means a function receives a copy of the passed value, and there's no way for the function to directly change a variable in the caller.
For example, if you write
void set_to_5(int x)
{
x = 5;
}
and then write
int i = 3;
set_to_5(i);
printf("%d\n", i);
it prints 3, not 5. Or, if you write
void set_string(char *str)
{
str = "world";
}
and then write
char *p = "hello";
set_string(p);
printf("%s\n", p);
it prints hello, not world.
In both cases, the function successfully changes its copy of the passed value — x or str — but that doesn't have any effect on the variable in the caller (i or p).
When you want to have a function that does change a variable in its caller, one way to do that is to have the function accept a pointer. That looks like this:
void set_to_5_via_pointer(int *x)
{
*x = 5;
}
void set_string_via_pointer(char **str)
{
*str = "world";
}
Then you can write:
int i = 3;
set_to_5_via_pointer(&i);
printf("%d\n", i);
char *p = "hello";
set_string_via_pointer(&p);
printf("%s\n", p);
Now it does print 5 and world, as desired.
Notice that in each case I made three changes:
I added a * to the parameter type expected by the function (int x to int *x, char *str to char **str)
I added a * before each use of the parameter in the function, that is, where I actually set the new value (5 and "world")
I added a & before the variables where I passed them to the function (set_to_5_via_pointer(&i) and set_string_via_pointer(&p)).
One more thing. When you see a function declaration like
void set_string_via_pointer(char **str);
this does not necessarily mean that the right way to call the function is
char **x;
set_string_via_pointer(x);
Yes, here x is of type char **, and function set_string_via_pointer expects an argument of type char **, so it's a match. But if you declare and call
char *y;
set_string_via_pointer(&y);
that's also a perfectly good way to pass an argument of type char **, and in this case, it's certainly they way that was expected.
const char* b = nullptr;
fun(&b);
This passes the pointer b by reference — or emulates pass by reference semantics — i.e. the memory address of where the variable is stored is passed instead of its value. This allows you to access the pointer originally declared in the calling function, and any changes made to that pointer in the called function would be visible in the calling function.
const char** b = nullptr;
fun(b);
Au contraire, this passes b by value. If you change the pointer to point to some other memory location in the called function, that change will not be reflected back in the calling function. Any attempt to dereference it while it is pointing to NULL would result in undefined behaviour as per the following clauses of C11:
If an invalid value has been assigned to the pointer, the behavior of
the unary * operator is undefined.
[...]
Among the invalid values for dereferencing a pointer by the unary *
operator are a null pointer, [...]
[6.5.3.2 Address and indirection operators, C11]
why use 1 but not 2?
Why use either of them?
1 is good, 2 donnot work
“There is nothing either good or bad, but thinking makes it so.” — They both serve different purposes. Though, the purpose of the second snippet is rather ambiguous here.
This code snippet
void fun(const char** a) {...}
1.
const char* b = nullptr;
fun(&b);
means passing the pointer b to the function fun by reference in the C meaning. So dereferencing the pointer to pointer a within the function you can change the original pointer b passed to the function indirectly through a pointer to it.
Here is a demonstration program.
#include <stdio.h>
void fun( const char **a )
{
*a = "Hello World!";
}
int main( void )
{
const char *b = NULL;
fun( &b );
puts( b );
}
The program output is
Hello World!
As you can see the pointer b is passed to the function indirectly through a pointer to it (by reference in the C meaning). Thus dereferencing the pointer to pointer a
*a = "Hello World!";
you can change the original pointer b defined in main.
In the second case
2.
const char** b = nullptr;
fun(b);
the pointer b is passed by value and if the function fun will dereference the null pointer then undefined behavior will be invoked.

Behaviour of 'int a' and 'int a[]' when we modify them outside of main() without the use of pointers [duplicate]

This question already has answers here:
Passing an array as an argument to a function in C
(11 answers)
Closed 1 year ago.
An element of an array can be changed like this.
#include <stdio.h>
void func(int a[]){
a[0] = 56;
}
int main()
{
int a[1]={34};
func(a);
printf("%d" ,a[0]);
return 0;
}
But when the array is replaced by just 'int a'; it remains unchanged. Or in other words, to change value of 'int a' from outside main(), pointers are required. What is the reasoning behind this? Why can an array be changed from a function without pointers but a simple 'int a' requires a pointer for modification?
To change an object in a function you need to pass it by reference. Otherwise the function will deal with a copy of the value of the passed object.
In C passing by reference means passing an object indirectly through a pointer to it.
This function declaration
void func(int a[]){
a[0] = 56;
}
is equivalent to
void func(int *a){
a[0] = 56;
}
due to adjusting by the compiler a parameter having an array type to pointer type to the array element type.
So in the above function elements of the array are passed in fact by reference. That is having a pointer to the first element of an array and the pointer arithmetic you can change any element of the array.
To change the same way a scalar object you need to pass it through a pointer to it.
To make the difference visible then if you have for example a function like
void func( int value )
{
value = 56;
}
And in main you have
int x;
func( x );
then the function call may be imagined the following way
void func( /*int value */ )
{
int value = x;
value = 56;
}
As you can see it is the local variable value initialized by the value of the variable x that is changed.
On the other have if you have a function like
void func( int value[] )
{
value[0] = 56;
}
and in main you have
int a[1];
func( a );
then the function call may be imagined the following way
func( &a[0] );
void func( /* int value[] */ )
{
int *value = &a[0];
value[0] = 56;
}

When to use Single Pointer over Double Pointer in C [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 1 year ago.
I have a question about pointer.
Recently, I was looking some system programming tutorial. The teacher is talking about asprintf() Function.
According to the man page, the definition of asprintf() is:
int asprintf(char **ret, const char *format, ...);
However, I found that the teacher tends to create a single pointer and then pass the address of that single pointer to the first parameter. Like this:
int main()
{
char *buffer;
int r;
r = asprintf(&buffer,"The total is %d\n",5+8);
puts(buffer);
printf("%d characters generated\n",r);
return(0);
}
I am wondering why don't we declare double pointer and then pass that double pointer to the function, just like the definition.
In addition, the teacher use the same tricks in other function too, such as: getline()
Therefore, is there any advantage that we would choose single pointer over double pointer, even the definition of the function is double pointer?
Thanks for everyone for replying in advanced. :))
asprintf will allocate some memory and write the printf result into that memory.
To get this resulting memory buffer, you pass a pointer to a local variable (in your case: buffer) as the first argument. This pointer is then dereferenced in the function, to change the value of your local variable, so the code in asprintf semantically does something like this:
int asprintf(char **ret, const char *format, ...) {
*ref = malloc(some_size);
sprintf(*ret, format, ...);
}
What would now happen if you didn't have a local variable of type char * and passed a pointer to this variable, but instead had a local variable of type char **, like you suggested:
char **buffer;
asprintf(buffer, "The total is %d\n", 5+8);
Well, asprintf would again just dereference this pointer you just passed. But in this code, it doesn't yet point to anything meaningful, so this would result in an error. We must have enough memory allocated at the address we are passing to asprintf so it can store a char* there for us.
Now, this would work:
char *buffer;
char **pointer_to_buffer = &buffer;
asprintf(pointer_to_buffer, "The total is %d\n", 5+8);
but it is just more complicated and verbose.
But why do we do this whole pointer-to-pointer thing? Well, you would certainly first try to simply pass the pointer, instead of a pointer-to-pointer, like this:
char *buffer;
asprintf(buffer, "The total is %d\n", 5+8);
with asprintf semantically doing something like this:
int asprintf(char *ret, const char *format, ...) {
ref = malloc(some_size);
sprintf(ret, format, ...);
}
However, it is critical that here, buffer is passed by value. This means that when asprintf locally modifies ret, it modifies a copy of the value of our buffer. We, the caller, will not be able to see this change in our variable buffer. This is why we pass a pointer-to our local variable buffer, not the value itself.
I am wondering why don't we declare double pointer and then pass that double pointer to the function, just like the definition.
Because you want to update the value stored in buffer. The type of the expression &buffer is char **.
Remember, in order for a function to write to any of its parameters, you must pass a pointer to that parameter:
void foo( T *ptr )
{
*ptr = new_T_value(); // writes a new value of type T to the thing ptr points to
}
void bar( void )
{
T var;
foo( &var ); // writes a new value to var
}
Thus, the following are true:
ptr == &var // T * == T *
*ptr == var // T == T
IOW, writing to the expression *ptr is the same as writing to var.
So, why not just create a pointer variable in bar and pass it to foo? If we wrote something like
void bar( void )
{
T *vptr;
foo( vptr );
}
the problem is that vptr doesn't point to anything meaningful - we have
ptr == vptr // T * == T *
*ptr == *vptr == ??? // T == T == ???
There's no object of type T for us to update. Now, we could create another object for vptr to point to:
void bar( void )
{
T var;
T *vptr = &var;
foo( vptr );
}
and that will work as expected, but the extra pointer variable is redundant in this case.
The same logic holds for pointer objects - let's replace T with a pointer type, P *. Then our code becomes:
void foo( P * *ptr ) // or P **ptr
{
*ptr = new_P_star_value(); // writes a new value of type P * to the thing ptr points to
}
void bar( void )
{
P * var; // or P *var
foo( &var ); // writes a new value to var
}
which gives us
ptr == &var
*ptr == var == some_P_star_value
**ptr == *var == *some_P_star_value == some_P_value
Same thing as above - we want to write a new value to var. To do that we pass a pointer to it, even though var is already a pointer type. This is why multiple indirection exists in the first place.
Most of the time when you see a function that has a pointer or pointer-to-pointer parameter, it's expecting you to pass the address of another object (obtained with the & operator), not a pointer variable as such.
If you want to change an object used as an argument in a function you need to pass it by reference.
In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer a function can get a direct access to the original pointer.
Consider this demonstrative program and compare the result of calls of the two functions f and g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f( char *s )
{
s = malloc( 14 );
strcpy( s, "Hello World!" );
}
void g( char **ps )
{
*ps = malloc( 14 );
strcpy( *ps, "Hello World!" );
}
int main(void)
{
char *s = NULL;
f( s );
if ( s != NULL ) puts( s );
else puts( "s is a null pointer." );
g( &s );
if ( s != NULL ) puts( s );
else puts( "s is a null pointer." );
free( s );
return 0;
}
The program output is
s is a null pointer.
Hello World!
The function f accepts the pointer s declared in main by value. It means that the function deals with a copy of the value of the pointer s. Changing the copy does not affect the original pointer s. So the function produces a memory leak because it allocates dynamically a memory and the address of the allocated memory stored in the local variable (function parameter) s will be lost after exiting the function.
The function g accepts the pointer s by reference through a pointer to it. So dereferencing its parameter the function has a direct access to the original pointer s and can change it.

Using Double Pointers in Memory Location [duplicate]

This question already has answers here:
What does ** do in C language? [duplicate]
(14 answers)
Closed 1 year ago.
I'm trying to understand purpose and how it's works double pointer in this code.
Why we use **p in the declaring function but inside the function we used *p?
void allocate(int** p)
{
*p = (int*)malloc(sizeof(int));
}
int main()
{
int *p = NULL;
allocate(&p);
*p = 42;
}
The function's parameter p has type pointer-to-pointer to int, i.e. int **. So referring to p refers to an object of that type.
The expression *p dereferences p giving you an expression (which is also an lvalue) of type int *. This matches the type of p in the main function, and actually refers to that object. This allows us, inside the function allocate, to modify the value of p in main to contain the address of a dynamically allocated block of memory.
To change the original pointer p declared within the function main in function allocate you need to pass it by reference. Otherwise the function will deal with a copy of the value of the original pointer p and changing the copy will not influence on the value stored in the original pointer.
In C passing by reference means passing an object indirectly through a pointer to it. So dereferencing the pointer you will get an access to the original object.
Consider the following demonstrative program.
#include <stdio.h>
void f( int x )
{
x = 20;
}
int main(void)
{
int x = 10;
printf( "Before calling the function d c = %d\n", x );
f( x );
printf( "After calling the function d c = %d\n", x );
return 0;
}
Its output is
Before calling the function d c = 10
After calling the function d c = 10
As you can see the original variable x was not changed after calling the function f because the variable is passed by value to the function.
Now consider the following program.
#include <stdio.h>
void f( int *px )
{
*px = 20;
}
int main(void)
{
int x = 10;
printf( "Before calling the function d c = %d\n", x );
f( &x );
printf( "After calling the function d c = %d\n", x );
return 0;
}
At this time the program output is
Before calling the function d c = 10
After calling the function d c = 20
As the variable x was passed by reference then dereferencing the pointer
px
*px = 20;
you get a direct access to the original variable x through the pointer.
So if you want to change a pointer itself then passing it by reference means passing a pointer to the pointer the same way as it was done in the function above only now the type of the original variable p is int * instead of int.
That is if you have a declaration like this
T x;
where T is some type (as for example int or int *) then to pass the variable by reference you need to use a function argument expression like &x. that will have the type T *. If T is equivalent to the type int * then you need to use an argument expression of the type int **.

Why is this passing by value? [duplicate]

This question already has answers here:
Passing char pointer in C
(5 answers)
Closed 6 years ago.
I'm trying to understand the difference between pass by value and pass by reference, and I thought that I finally understand it, until I saw this code :
void change(char *p1)
{
p1="new";
}
int main()
{
char *txt1=(char*)malloc(200*sizeof(char));
txt1="original";
printf("before :%s\n",txt1);
change(txt1);
printf("after :%s\n",txt1);
}
Isn't it passing an address ? and then changing it and making it point to somewhere else ?
The output is :
before : original
after : original
Why is that?
There is no pass-by-reference in C. Function parameters are passed using pass-by-value. That is, p1 itself is passed by value. You can change the content of the memory address pointed to by p1 (*p1) from the called function, not p1 itself.
To clarify, for changing the content of a variable var, you need to pass the address of var, so, if you want to change a pointer itself, you need to pass the address of the pointer to the function.
That said, please see this discussion on why not to cast the return value of malloc() and family in C.
This is passing an address as value. To have the callee modify caller's local variable, pass address of what should be modified.
#include <stdio.h>
void change(char **p1)
{
*p1="new";
}
int main(void)
{
char *txt1; /* no causing memory leak */
txt1="original";
printf("before :%s\n",txt1);
change(&txt1);
printf("after :%s\n",txt1);
}
Pass By Reference and Pass By value.
Here's an example I've used before. Assume the following two functions:
void foo( T *p ) // where T is an arbitrary data type
{
*p = new_value(); // write new value to the thing p points to
}
void bar( void )
{
T var;
foo( &var ); // write new value to var
}
For function foo to update the contents of var (an object of type T) we must pass a pointer to var (type T *).
If we replace T with a pointer type P *, then the above code becomes
void foo( P **p )
{
*p = new_value(); // write new value to the thing p points to
}
void bar( void )
{
P *var;
foo( &var ); // write new value to var
}
The semantics are exactly the same; we want foo to write a new value to var, so we pass a pointer to var. It's just that in this case, var is already a pointer type, so we wind up passing a pointer to a pointer.
Basically, for foo to update the contents of var, you must pass the expression &var as the argument, meaning the type of the formal parameter p will always have one more level of indirection than the type of var.
Type of var Type of &var Type of p
----------- ------------ ---------
T T * T *
T * T ** T **
T ** T *** T ***
etc.
In function call change(txt1);, txt1 is passed by value. It is copied to the parameter p of function change. This makes pi points to the same string as txt1 pointing to. When new string is assigned to p1 then p1 changes to point to that string while txt1 pointing previous one.
this case is very similar to
char *s1 = "String";
char *s2 = s1; // Both s1 and s2 points to same string
s2 = "Another string" // Now s2 points to "Another string" while s1 pointing to "String".
Beside that your code is causing memory leak. It should be like
char *txt1=(char*)malloc(200*sizeof(char));
strcpy(txt1,"original");

Resources