Simple clarification about pass by reference vs. pass by value - c

I declare a variable (of type TEST containing a static array) and call several functions passing a pointer to this variable.
typedef struct
{
char data[50];
} TEST;
int main(int argc,char *argv[])
{
TEST *ptr = malloc(sizeof(TEST));
func_one(ptr);
printf("data: %s\n", ptr->data);
}
void func_one(TEST *ptr)
{
func_two(ptr);
}
void func_two(TEST *ptr)
{
strcpy(ptr->data, "hello");
}
Will the above print statement print "hello"? My program currently prints "hello", but I am confused because from my understanding, I know that ptr is being passed by value, rather than by reference.

You're right, the pointer is passed by value, so the pointer ptr in the main function is copied to the ptr variable in func_one, and it is in turn copied to the ptr variable in func_two.
You are, however, not trying to modify the pointer, but the data it points to, so it's the data is passed by reference, but the pointer to the data is not.
Though technically C doesn't have "pass by reference", it can only be emulated by using pointers.
Also, you would have the same outcome it you didn't allocate the data on the heap, and used the address-of operator:
TEST data;
func_one(&test);

The pointer is being passed by value, that is correct. That means that the array that is being pointed to is passed by reference.
(I have a feeling that in the purest Computer Science sense that may be incorrect but it is close enough for all practical purposes).

Pass-by-reference means you're passing a reference to some data. Pass-by-value means you're passing a copy of some data.
In this case, you're passing a pointer by value. But what's a pointer? It's a reference to some data.
You're passing the pointer itself by value, but given that it's a pointer, the side effect is that any data it points to is essentially passed by reference.

Related

C - Unable to retrieve const char* value [duplicate]

Is passing pointer argument, pass by value in C++? Since i see that any change to the pointer as such is not reflected outside the method. The changes i do by dereferencing the pointer is reflected though.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
Yes to both.
Pointers are passed by value as anything else. That means the contents of the pointer variable (the address of the object pointed to) is copied. That means that if you change the value of the pointer in the function body, that change will not be reflected in the external pointer that will still point to the old object. But you can change the value of the object pointed to.
If you want to reflect changes made to the pointer to the external pointer (make it point to something else), you need two levels of indirection (pointer to pointer). When calling functions it's done by putting a & before the name of the pointer. It is the standard C way of doing things.
When using C++, using references is preferred to pointer (henceforth also to pointer to pointer).
For the why references should be preferred to pointers, there is several reasons:
references introduce less syntaxic noise than pointers in function body
references keep more informations than pointers, than can be useful for compiler
Drawbacks of references are mostly:
they break the simple pass-by-value rule of C, what makes understanding the behavior of a function regarding of parameters (will they be changed ?) less obvious. You also need function prototype to be sure. But that is not really worse than the multiple pointer levels necessary when using C.
they are not supported by C, that can be a problem when you write code that should work with both C and C++ programs (but that's not the most usual case).
In the specific case of pointer to pointer, the difference is mostly simplicity, but using reference it may also be easy to remove both levels of pointers and pass only one reference instead of a pointer to pointer.
I understand the confusion here. The concepts of "pass by value" and "pass by reference" are not so clear even if they seem to be so.
Bear in mind that the computer does not know these concepts and does not behave according to it.
The computer does not know about the types. Hence it does not make a distinction of pointers and values.
Let me try to explain by and example:
void func1(int x) //copy some value to local variable x (of type int)
{
x = 5; //modify local variable. lost after function call
}
void func2(int *x) //copy some value to local variable x (of type int*)
{
int a;
x = &a; //modify local variable. lost after function call.
}
void func3(int *x) //copy some value to local variable x(of type int*)
{
*x = 10; //x is local but *x is not! change is saved after function call!
}
func1 and func2 are identical. Both modify a local variable. Modification is lost after function is popped off the stack.
func3 has ability to change another memory location (a variable which is not local to the function).
basically, every function call is "call by value". But in the case of a pointer type, we have a way to change the content of a remote address in memory.
Pass by value using Pointers
I'll explain it by example:
void f(int *ptr)
{
cout<<*ptr;
}
int main ()
{
int a=10;
int *aptr=&a;
f(aptr);
return 0;
}
Here, in main function a is an integer variable whose content is 10 and address is 00F8FB04 (assume).
aptr is pointer to integer, that store the address of integer variable a, so aptr content is address of integer variable a that is 00F8FB04. When we pass aptr as the function argument only content of aptr (that is address) are copies to function parameter.
So, ptr will receive the copy of content of aptr (that is address 00F8FB04)
Either a pointer to a pointer, or a reference to a pointer, is what you would use if you wanted to potentially change the pointer itself. To your original question, technically, yes, all parameters are passed by value.
Yes it is, as it is in C.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
In which case? What do you want? You can use real references with the & modifier.
void func(type &ref);

Is passing pointer by value or by reference the same

What is the difference between passing a pointer by reference and passing a pointer by value in C?
My understanding is when you pass arguments to methods a new stack frame is created and those values are copied to different memory addresses unless passed by reference. If passed by reference the memory addresses are passed.
When working with pointers I noticed that if I pass a char* by value and modify it in a different stack frame when I return back to the main stack frame the value of the ptr has been modified.
I wrote short code to show what I am talking about.
//test pointer ref
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void passbyval(char const *lit,char* str){
printf("---passbyval---\n");
printf("%s\t%p\n",lit,&lit);
//modify string
strncat(&str[2],"/",1);
printf("%s\t%p\n",str, &str);
}
void passbyref(char const **lit, char** str){
printf("---passbyref---\n");
printf("%s\t%p\n",*lit,&*lit);
//modify string
strncat(&(*str)[1],"/",1);
printf("%s\t%p\n",*str,&*str);
}
int main(){
char const *litstr = "hello this is a test";
char *str = (char*)malloc(sizeof(char)*100);
scanf("%[^\n]",str);
printf("---main---\n");
//print original value and address
printf("%s\t%p\n",litstr,&litstr);
printf("%s\t%p\n",str,&str);
passbyval(litstr,str);
//modified value and address from pass by value
printf("\nretfromval:%s\t%p\n",str,&str);
passbyref(&litstr,&str);
//modified value and address from pass by ref
printf("\nretfromref:%s\t%p\n",str,&str);
free(str);
return EXIT_SUCCESS;
}
Output
Is it good practice to not pass by reference char* you want to modify in void methods?
Scratching my head on why I would ever use pass by reference for pointers if the value they are referencing are implicitly passed by reference.
Maybe I'm missing something can some explain this a little better?
When working with pointers I noticed that if I pass a char* by value and modify it in a different stack frame when I return back to the main stack frame the value of the ptr has been modified.
None of your examples do this. Also, none of your code prints the value of litstr or str. To print the values of the pointers, remove the & in all of your printf calls. Then you will see the values of the pointers are the same in the calling routine and the called routine.
In main, printf("%s\t%p\n",litstr,&litstr); prints:
the string that starts in memory at the address that is the value of litstr (because of %s and litstr) and
the address (not the value) of litstr (because of %p and &litstr).
Similarly, printf("%s\t%p\n",str,&str); prints the string at str and the address of str.
In passbyval, printf("%s\t%p\n",lit,&lit); prints the string at lit and the address of lit. Since lit is a parameter to passbyval, it has its own address, which is different from the address of litstr. If you had printed the values of litstr and lit, instead of their addresses, you would see they are the same.
Similarly, printf("%s\t%p\n",str, &str); prints the string at str and the address of str. The address of the parameter str in passbyval is different from the address of the local object str in main, but their values are the same.
In passbyref, printf("%s\t%p\n",*lit,&*lit); prints the string at lit and the address of *lit. Since lit is the address of the litstr in main, *lit is that litstr, so &*lit is the address of litstr. The value of litstr would be *lit.
Similarly, printf("%s\t%p\n",*str,&*str); prints the string at *str and the address of *str, which is the address of str in main.
What is the difference between passing a pointer by reference and passing a pointer by value in C?
There is no such thing as passing a pointer by reference in C, all variables are passed by value, even pointers.
My understanding is when you pass arguments to methods a new stack frame is created and those values are copied to different memory addresses unless passed by reference. If passed by reference the memory addresses are passed.
Again, the pointers are not passed by reference, a copy of the value stored in the pointer is passed, i.e. the address where it points to, you can test this by changing the value of the pointer inside the function, and check how that reflects on the original pointer, spoiler, it doesn't.
When working with pointers I noticed that if I pass a char by value and modify it in a different stack frame when I return back to the main stack frame the value of the ptr has been modified.*
What you are passing is an address, a memory location where some data is stored, when you change the data stored in that memory address it will be permanent, no matter where you do it, in fact that is one of the advantages of using pointers, for you to change the contents of some variable outside the scope where it's declared.
You need to understand how the pointers and arrays work.
pointer is a separate object having its own reference, holding the reference of the underlying object.
char *p = "aaa";
print("%p\n", (void *)p); //prints the reference of the string literal "aaa"
print("%p\n", (void *)&p); //prints the reference of the pointer `p`
Arrays are contignous chunks of memory. Arrays decay to pointers. Those pointers do not have physical representation in the memory and only are references to the first element of the array.
char p[] = "aaa";
print("%p\n", (void *)p); //reference of the first element
//of the array p the type is `char *`
//(pointer to char)
print("%p\n", (void *)&p); //reference of the first element of the
//array p the type is `char (*)[4]`
//(pointer to an array of 4 char elements)
What is the difference between passing a pointer by reference and passing a pointer by value in C.
In C, there are various ways arguments are pre-processed before being passed to a function.
No processing
A copy of the argument is given to the function. char *s = ...; puts(s);. puts() is given a copy of s.
Usual argument promotion
The argument is promoted to int, unsigned, double, ... before a copy is given to the function. float fl = 12.5f; printf("%g", fl); printf() is given a copy of double 12.5.
Function converted to an address
With tss_create(tss_t *key, tss_dtor_t dtor);, tss_dtor_t is a function pointer type void (*)(void*). tss_create(... , foo) does not take a function foo() and pass that. Instead a copy of the address of the function is passed.
Array converted to address of its first element
With char s[] = "Hello; puts(s);, A copy of &s[0] is passed to puts().
Now, are any of these like OP's pass by reference?
Yes.
With char *end[1]; strtod("123.4", end);, from the caller's point of view, end is adjusted in it entirety by strtod() and so acts and smells like "pass by reference" from the caller's POV. This is technically still "pass a copy", but the copy is the address of the argument's 1st element.
Other than that, I see no comparable "passing a pointer by reference and passing a pointer by value in C" in which to find a difference.

What's the point of having a pointer to pointer to struct as argument?

I'm learning how to program for ALSA in Linux and there's a piece of code like this:
snd_pcm_t * _soundDevice;
bool Init(const char *name)
{
int i;
int err;
snd_pcm_hw_params_t *hw_params;
if( name == NULL )
{
// Try to open the default device
err = snd_pcm_open( &_soundDevice, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0 );
}
As you can see, it first creates the pointer to the struct snd_pmc_t and name it _soundDevice. Other parts of the code, however, use only the first pointer:
if ((err = snd_pcm_hw_params_any (_soundDevice, hw_params)) < 0)
I understand that a pointer to a struct is helpful to pass as an argument because passing the entire struct as a copy would be bad, and I also understand that this function modifies the content of the struct that the pointer points to, but why should somebody need a pointer to a pointer to a struct?
why should somebody need a pointer to a pointer to a struct?
This most often shows up when you need to pass a pointer into a function in a way that allows the function to change what that pointer points to. One idiomatic C way is to pass the pointer by pointer, resulting in that second level of indirection you're wondering about.
In your example snd_pcm_open modifies its first argument (i.e. makes _soundDevice point someplace new), whereas snd_pcm_hw_params_any doesn't.
If snd_pcm_open were to take snd_pcm_t* rather than snd_pcm_t**, it wouldn't be able to repoint the first argument in a manner that would propagate back to the caller.
In C, parameter passing is by value (or by copy if you prefer), so if you want a function to modify the passed argument in return you need to pass its address.
Having a pointer to a pointer allows the function to modify your local pointer. If you passed just a regular pointer, the function gets that pointer on the stack. If it modifies that value (of the pointer, not the pointed-to data), the value is lost when the function returns the same way that changes to an int passed to a function would be lost. If you instead pass a pointer to a pointer, it can modify your pointer, which will still exist after the function returns.
If, for instance, the function is allocating memory for that structure, it can set your pointer to the address of the newly allocated memory or NULL if the allocation fails. In this case, it looks like this is being used as a second return value. It wants to return an error code as the actual return value and a pointer as a second value.
Some times the target is not to change an object, but to change the pointer that points to it.
Imagine a function 'A' that choses among several functions
int A(someType* funcChosen)
{
funcChosen = ...; //a pointer to a function
}
someType* myFunc;
int res = A(myFunc);
will modify myFunc. But you want a pointer to that function, not the code (??) of it. So better:
int A(someType** funChosen);
someType* myFunc;
int res = A(&myFunc);

Assigning a new adress to a pointer in a function not possible? [duplicate]

This question already has answers here:
change pointer passed by value
(6 answers)
Closed 7 years ago.
I had a programming assignment a while back where I stumbled upon this little problem: when I gave a function a pointer as a parameter, I could not change the address it pointed at. I solved that by returning the new adress I wanted the pointer to point to. But I am still wondering why it's not possible to manipulate a pointer parameter because all memory allocating functions work with a return value as well instead of a parameter list.
Was I possibly doing something wrong? Or is it really not possible to change the pointee? Does anyone have an explanation?
Example:
void foo(int *ptr)
{
ptr=malloc(sizeof(int));
} /* after calling this function I would
expect the pointee to have changed to the
newly allocate memory but it stays NULL*/
int main()
{
int *ptr=NULL;
foo(ptr);
return 0;
}
It's because all parameters are passed by value in C. If you call a function with a pointer parameter you may change that pointer in the function but this will have no effect on the caller's value of the pointer.
If you need to communicate a modified pointer back to the caller, returning the modified pointer is the way to go. Note that this also only passes a value back.
Another way would be to pass the address of a pointer (i.e. a pointer to a pointer). The called function can then store a new pointer value at the given address.
Memory allocating functions return the pointer value, so it is generally
assigned to a pointer.
Passing a pointer to a function as an argument is a different story,
because changing it won't change the original (pass by value). That's
why we use pointers in these cases, to give the address of a variable
and change its value in the function.
If you need to pass a pointer instead, and change what it points to, use
a pointer to a pointer!
void
my_function(int **pointer)
{
*pointer = &something; // will change the pointer address
}
int *my_pointer = &something_else;
my_function(&my_pointer);

Store pointer value

As I know, when a pointer is passed into a function, it becomes merely a copy of the real pointer. Now, I want the real pointer to be changed without having to return a pointer from a function. For example:
int *ptr;
void allocateMemory(int *pointer)
{
pointer = malloc(sizeof(int));
}
allocateMemory(ptr);
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays? Not by subscript, but by pointer arithmetic. Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself. For example:
int *a;
why not:
allocateMemory(*a)
but
allocateMemory(a)
I know I always have to do this, but I really don't understand why. Please explain to me.
The last thing is, in a pointer like this:
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer? I always think a is the memory address of the actual value it is pointing, but I am not sure about this. By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
I'll try to tackle these one at a time:
Now, I want the real pointer to be changed without having to return a pointer from a function.
You need to use one more layer of indirection:
int *ptr;
void allocateMemory(int **pointer)
{
*pointer = malloc(sizeof(int));
}
allocateMemory(&ptr);
Here is a good explanation from the comp.lang.c FAQ.
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays?
One allocation for the first dimension, and then a loop of allocations for the other dimension:
int **x = malloc(sizeof(int *) * 2);
for (i = 0; i < 2; i++)
x[i] = malloc(sizeof(int) * 3);
Again, here is link to this exact question from the comp.lang.c FAQ.
Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
ABSOLUTELY NOT. Pointers and arrays are different. You can sometimes use them interchangeably, however. Check out these questions from the comp.lang.c FAQ.
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself?
why not:
allocateMemory(*a)
It's two things - C doesn't have pass-by-reference, except where you implement it yourself by passing pointers, and in this case also because a isn't initialized yet - if you were to dereference it, you would cause undefined behaviour. This problem is a similar case to this one, found in the comp.lang.c FAQ.
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer?
That question doesn't really make sense to me, but I'll try to explain. a (when correctly initialized - your example here is not) is an address (the pointer itself). *a is the object being pointed to - in this case that would be an int.
By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
Correct in both cases.
To answer your first question, you need to pass a pointer to a pointer. (int**)
To answer your second question, you can use that syntax to access a location in an existing array.
However, a nested array (int[][]) is not the same as a pointer to a pointer (int**)
To answer your third question:
Writing a passes the value of the variable a, which is a memory address.
Writing *a passes the value pointed to by the variable, which is an actual value, not a memory address.
If the function takes a pointer, that means it wants an address, not a value.
Therefore, you need to pass a, not *a.
Had a been a pointer to a pointer (int**), you would pass *a, not **a.
Your first question:
you could pass a pointer's address:
void allocateMemory(int **pointer) {
*pointer = malloc(sizeof(int));
}
int *ptr;
allocateMemory(&ptr);
or you can return a pointer value:
int *allocateMemory() {
return malloc(sizeof(int));
}
int *ptr = mallocateMemory();
I think you're a little confused about what a pointer actually is.
A pointer is just variable whose value represents an address in memory. So when we say that int *p is pointer to an integer, that just means p is a variable that holds a number that is the memory address of an int.
If you want a function to allocate a buffer of integers and change the value in the variable p, that function needs to know where in memory p is stored. So you have to give it a pointer to p (i.e., the memory address of p), which itself is a pointer to an integer, so what the function needs is a pointer to a pointer to an integer (i.e., a memory address where the function should store a number, which in turn is the memory address of the integers the function allocated), so
void allocateIntBuffer(int **pp)
{
// by doing "*pp = whatever" you're telling the compiler to store
// "whatever" not in the pp variable but in the memory address that
// the pp variable is holding.
*pp = malloc(...);
}
// call it like
int *p;
allocateIntBuffer(&p);
I think the key to your questions is to understand that there is nothing special about pointer variables. A pointer is a variable like any other, only that the value stored in that variable is used to represent a position in memory.
Note that returning a pointer or forcing the caller to move the pointer in an out of a void * temp variable is the only way you can make use of the void * type to allow your function to work with different pointer types. char **, int **, etc. are not convertible to void **. As such, I would advise against what you're trying to do, and instead use the return value for functions that need to update a pointer, unless your function by design only works with a specific type. In particular, simple malloc wrappers that try to change the interface to pass pointer-to-pointer types are inherently broken.

Resources