copy string to pointer failed in function in Clang - c

below clang code run in ubuntu 18.04.2 LTS
I expect to output ptr3=123 the same as var ptr2,
But the result is ptr3=(null). How to modify the code that the result as I want?
#include <stdio.h>
void ptr_copy(char* d, char* s)
{
d = s;
}
int main(){
char *ptr = "123";
char* ptr2;
char* ptr3;
ptr2 = ptr;
ptr_copy(ptr3, ptr);
printf("ptr2=%s\n", ptr2);
printf("ptr3=%s\n", ptr3);
// output
// ptr2=123
// ptr3=(null)
}

Lets take a look at your "copy" function:
void ptr_copy(char* d, char* s)
{
d = s;
}
In the function the variable d is a local variable. The assignment to it will be lost once the function returns and d goes out of scope and ends its life.
That leaves you with an uninitialized ptr3 variable in the main function, and using it will lead to undefined behavior-
If you want to copy the pointer, you need to emulate pass by reference by passing a pointer to the pointer itself:
void ptr_copy(char** d, char* s)
{
*d = s;
}
and call it as
ptr_copy(&ptr3, ptr);

what you need is a different ptr_copy function, something like this:
void ptr_copy(char** dst, char* src) {
(*dst) = src;
}
ptr_copy(&ptr3, ptr);
the idea is that you fill the content of ptr to the place where ptr3 is stored (hence &ptr3, not ptr3).
When you pass a pointer to a function, the value of that pointer is passed (that is an address a given pointer points to). Thus pointer d within ptr_copy is a different pointer than ptr3 (it has a same value as ptr3 but it resides in another part of the memory). That's why the assignment d = s, change an address d points to, but it doesn't do anything with ptr3.
Indeed consider a function
void value_copy(int d, int s) {
d = s;
}
int i1 = 3;
int i3 = 2;
value_copy(i3, i1);
You don't expect i3 to be equal to 3 after the call of value_copy(), do you?

Related

Change the value of the pointer inside a function

I wanted to change the value of a pointer to point to a different address from inside a function.
I know I need a pointer to pointer to do that but I made a typo mistake and used char * instead of char ** and I got the results below.
Passing the address of the pointer ptr1 in the function func, the pointer p becomes a pointer that points to the address of a pointer.
So if I dereference the pointer *p I'll be able to change the value that it points to, in that case the (value of) pointer ptr1.
I know I cannot access the data that ptr1 points to (I'd need a char ** p argument for that).
But if my only intention is to change the address that ptr1 points to, would that be acceptable in C?
#include <stdio.h>
char array1[10] = {'1','2','3','4','5','6','7',};
char array2[10] = {'A','B','C','D','E','F','G',};
void func(char * p)
{
printf("func is called\n");
*p = array2;
}
int main(void)
{
char * ptr1 = NULL;
ptr1 = array1;
printf("ptr1 = %s\n", ptr1);
func(&ptr1);
printf("ptr1 = %s\n", ptr1);
return 0;
}
This is the result I get.
ptr1 = 1234567
func is called
ptr1 = ABCDEFG
Your code is wrong and you (un)luckyly got the desired output with your wrong code.
The function func is modifying only one byte based on the passed pointer because the pointer is char*.
It seems you are using little-endian environment and the address of first elements of array1 and array2 happened to be same other than the lowest byte, so the value of ptr1 after the modification happened to be correct by modifying only one byte.
Try replacing
char array1[10] = {'1','2','3','4','5','6','7',};
char array2[10] = {'A','B','C','D','E','F','G',};
with
char array1[256] = {'1','2','3','4','5','6','7',};
char array2[256] = {'A','B','C','D','E','F','G',};
(change the number of elements of the arrays) and you may get another result. If you failed to get another result, try another size.

Pointers in functions and pointers in lists

When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable. For example:
void copy(int *p, int *s);
int main(){
int a = 4, b = 10, *p = &a, *s = &b;
copy(p, s);
}
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
So at the end of this, "b" is equal to "a", and "a" is equal to 0, even though "a" and "b" wouldn't normally be modifiable.
When talking about lists and, specifically, adding an element to a list, I can use a function like this:
struct list{
int n;
struct list *next;
}
struct list *first = NULL;
int main(){
int n = 3;
first = add_to_list(first, n);
}
struct list *add_to_list(struct list *first, int n){
struct list *new_node;
new_node = malloc(sizeof(struct list));
if(new_node == NULL) exit(EXIT_FAILURE);
new_node->value = n;
new_node->next = first;
return new_node;
}
What concerns me specifically is why the function can't simply return a type void, and instead of writing "return new_node", I can't simply write "first = new_node". Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
Also, bit of an unrelated question, but if I've got a function like this:
void first_to_n(int a[], int n){
a[0] = n;
}
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
Lets say we have something like the following code
void funcA(int x)
{
x = 0;
}
void funcB(int *y)
{
y = NULL;
}
int main(void)
{
int a = 10;
int *b = &a;
funcA(a);
funcB(b);
}
What happens when funcA is called is that the value of a is copied into the separate variable x inside the function. When the call is being made there are two copies of the value 10 stored in to different places. When the assignment x = 0 is done inside the function, only the local variable x is modified.
For funcB just the same happens. The value of the variable b is copied into the separate variable y in the function. That means there are two separate and distinct variable pointing to the same location. But once the assignment y = NULL is done, that's no longer true. The variable y is no longer pointing to the same location, but in the main function b is unmodifed since only a copy of the value was passed to the function.
If we now take a slightly different example
void func(int *x, int **y)
{
*y = x;
}
int main(void)
{
int a = 10;
int b = 20;
int *c = &a; // Make c point to the variable a
func(&b, &c);
}
After the function is called, then c does no longer point to a, it points to b. That's because for the second argument the value we pass is &c which is a pointer to the variable c. Inside the function we can then use the dereference operator to access what y is pointing to (which will be the variable c in the main function).
When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable.
Among other things, like creating non-trivial data structures and to avoid copies.
Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
first (the parameter) is a copy of first (the global). Therefore, first = new_node would only modify your pointer, not the global one.
This is more clear in your first example:
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
If you were doing p = 0;, for instance, you would only modify the pointer, not the value pointed to.
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
That is not a "vector" (array), it is a pointer even if it looks like an array. It is a big gotcha of C.
But, indeed, a[0] = 0; is modifying the first value (in main) pointed by the parameter.
What concerns me specifically is why the function can't simply return
a type void, and instead of writing "return new_node", I can't simply
write "first = new_node".
As the other answers explain, you can't due to first being a 'copy' of the pointer outside the function. If however you were to instead change the function such that you passed a 'pointer to the pointer' rather that just the 'pointer', then you could change the external value, which is what's going on the in the 'copy' function.
This uses a pointer to a literal string.
The pointer is pass to modifypointer() where it is modified to point to another literal string. The new literal string is printed in the function, but main() still prints the original.
The pointer is passed as a pointer to itself in modifypointertopointer() where it is dereferenced to point to another literal string. Now the function prints the new literal string and main() also prints the new literal string.
In your last example, first = new_node; could be used except the function declares a shadow variable first and the global first is no longer in the scope of the function.
#include <stdio.h>
void modifypointer( char *mod) {
mod = "modify pointer";
printf ( "%s\n", mod);
}
void modifypointertopointer( char **ptrmod) {
*ptrmod = "modify pointer to pointer";
printf ( "%s\n", *ptrmod);
}
int main( void) {
char *text = "original";
printf ( "%s\n", text);
modifypointer ( text);
printf ( "%s\n", text);
modifypointertopointer ( &text);
printf ( "%s\n", text);
return 0;
}

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.

usage of double pointers as arguments

Please find the code snippet as shown below:
#include <stdio.h>
int My_func(int **);
int main()
{
int a =5;
int *p = &a;
My_Func(&p);
printf("The val of *p is %d\n,*p);
}
void My_Func(int **p)
{
int val = 100;
int *Ptr = &val;
*p = Ptr;
}
How does by using a double pointer as a argument in my_Func function and making change of value reflects the same in the main function but if we use a single pointer in My_Func does not change the value in main?Please do explain me with examples if possible
Advanced thanks
Maddy
int **p is a pointer to a pointer-to-int. My_Func(int **p) works by changing the value of integer that the pointer-to-int points to i.e. int a.
Without changing the implementation, the function will not work with a pointer-to-int parameter int *p as there is a second level of indirection. In addition, you're setting the value to a local variable that is created on the stack. When the function is completed the memory used for the variable will be reclaimed, therefore making the value of a invalid.
void My_Func(int **p)
{
int val = 100; // Local variable.
int *Ptr = &val; // This isn't needed.
*p = Ptr;
} // val dissapears.
Remove the second level of indirection and copy val by value instead of pointing to it:
#include <stdio.h>
void My_Func(int *p)
{
int val = 100;
*p = val;
}
int main(void)
{
int a = 5;
My_Func(&a);
printf("The val of a is %d\n", a);
return 0;
}
In short, in C when you pass something as a parameter, a copy will be passed to the function. Changing the copy doesn't affect the original value.
However, if the value is a pointer, what it points to can be changed. In this case, if you want to affect the pointer, you need to pass a pointer to it down to the function.
Use it in the function declaration:
void func(int *p)
{
int val =100;
int *temp=&val;
p=temp;
}
p starts pointing to another address i.e. address of val. So it will print the value 100.
Important note: Try it in your downloaded compiler (always in case of pointers) not in the online compiler. The online compiler doesn´t keep track of lost addresses in stack.
You are assigning the address of local variable, which will soon disappear when My_Func returns. You can use following in your code. However you can do the same thing just by using single pointer, double pointer is not required in this example.
void My_Func(int **p)
{
int val = 100;
int *Ptr = &val;
**p = *Ptr;
}

void pointer as argument [duplicate]

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 3 years ago.
The following C snippet:
[...]
void f1(void* a){
printf("f(a) address = %p \n",a);
a = (void*)(int*)malloc(sizeof(int));
printf("a address = %p \n",a);
*(int*)a = 3;
printf("data = %d\n",*(int*)a);
}
void f(void){
void* a1=NULL;
printf("a1 address = %p \n",a1);
f1(a1);
printf("a1 address = %p \n",a1);
printf("Data.a1 = %d\n",*(int*)a1);
}
[...]
results in
a1 address = (nil)
f(a) address = (nil)
a address = 0xb3f010
data = 3
a1 address = (nil)
Segmentation fault (core dumped)
Why doesn't a1 keep the address that has been assigned to it in the function?
As this is C, you cannot pass the pointer by reference without passing in a pointer to the pointer (e.g., void ** rather than void * to point to the pointer). You need to return the new pointer. What is happening:
f(a1);
Pushes the value of the pointer (NULL) as the stack parameter value for a. a picks up this value, and then reassigns itself a new value (the malloced address). As it was passed by value, nothing changes for a1.
If this were C++, you could achieve what you want by passing the pointer by reference:
void f(void *&a);
Passing a pointer to a1 to your function, you can't change where a1 points. The pointer is passed by value, so in f1 you're only changing a copy of the address held by a. If you want to change the pointer, i.e. allocate new memory for the pointer passed in, then you'll need to pass a pointer to a pointer:
void f1(void **a)
{
// ...
*a = malloc(sizeof(int));
// ...
To change a variable via a function call, the function needs to have reference semantics with respect to the argument. C doesn't have native reference variables, but can implement reference semantics by means of taking addresses and passing pointers.
Generally:
void mutate_thing(Thing * x) // callee accepts pointer
{
*x = stuff; // callee derefences ("*")
}
int main()
{
Thing y;
mutate_thing(&y); // caller takes address-of ("&")
}
In your case, the Thing is void *:
void f(void ** pv)
{
*pv = malloc(12); // or whatever
}
int main()
{
void * a1;
f(&a1);
}
Based on Kerrek SB's example I came with this to demonstrate void pointer-to-pointer as an argument and how it may be used.
#include <stdio.h>
void test(void ** jeez)
{
*jeez = (void *) (int) 3;
}
int main (int argc, char* argv[])
{
void *a;
test(&a);
int b = *(int *)&a;
printf("value returned = %d\n", b);
return 0;
}

Resources