0

Already this question is been asked here: double pointer vs single pointer

I followed the instructions of this above question but facing segfaults and still unable to understand exactly whats happening in the memory (what points to what and how). Below is the code:

#include <stdio.h>
#include <stdlib.h>

void func(int **ptr)
{
    *ptr = (int *) malloc (sizeof(int));
    **ptr = 10;
    printf("Inside func: ptr: %p *ptr: %p **ptr: %p %d\n", ptr, *ptr, **ptr, **ptr);
}

void func2(int *ptr)
{
    int i = 10;
    ptr = (int *) malloc (sizeof(int));
    *ptr = 288;
    printf("Inside func2: ptr: %p *ptr: %p %d\n", ptr, *ptr, *ptr);
}

int main()
{
    int *a = NULL, *b = NULL;
    func(&a);
    printf("&a: %p, a: %p, *a: %p *a: %p %d\n", &a, a, *a, *a, *a);
    func2(b);
    printf("*b: %d\n", *b);
    return 0;
}

Output:

main.c:8:51: warning: format ‘%p’ expects argument of type ‘void *’, but argument 4 has type ‘int’ [-Wformat=]          
main.c:16:42: warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘int’ [-Wformat=]         
main.c:23:33: warning: format ‘%p’ expects argument of type ‘void *’, but argument 4 has type ‘int’ [-Wformat=]         
main.c:23:40: warning: format ‘%p’ expects argument of type ‘void *’, but argument 5 has type ‘int’ [-Wformat=]         
Inside func: ptr: 0x7ffcf5c49760 *ptr: 0x22f7010 **ptr: 0xa 10                                                          
&a: 0x7ffcf5c49760, a: 0x22f7010, *a: 0xa *a: 0xa 10                                                                    
Inside func2: ptr: 0x22f7030 *ptr: 0x120 288                                                                            
Segmentation fault (core dumped)

In func--> when a & ptr are assigned & pointing to same memory locations, why cant it happen to func2. Anyways for *ptr I am passing b (which is the address of *b) and changing the value.

Unable to understand what points to what and how. If someone could help will be very thankful.

Though its a repetition of already asked question, posted since the answer is insufficient for me to understand. Hence pls dont mark is as duplicate atleast until the question is been answered correctly.

Preethi
  • 43
  • 9
  • initialise *a and *b to NULL . Example : int *a = NULL; – RaHuL Feb 25 '20 at 07:39
  • 1
    Using wrong format specifiers causes undefined behaiour: `*ptr: %p %d\n", ...**ptr, **ptr);` `**ptr` is of type `int`, don't print it as a pointer. – Gerhardh Feb 25 '20 at 08:13
  • In main you write `*b` when `b` is a null pointer, that's what caused the segfault here – M.M Feb 25 '20 at 08:37
  • @M.M Thanks for the response. In func2 am trying to assign a memory but thats failing hence I am getting segfault. Trying to understand why my malloc is not working there. – Preethi Feb 25 '20 at 08:57
  • @Preethi `func2` has nothing to do with local variables of `main` – M.M Feb 25 '20 at 10:23
  • @M.M thanks for the response. Posted it to know how it works. Got it from TruthSeeker. Happy :) – Preethi Feb 25 '20 at 15:35

4 Answers4

1

The pointer b was never initialized, not in main and not in the function. It does not point to any valid memory block.

you can try the following. &b is a pointer to an integer.

int b = 0;

func2(&b);
eyalm
  • 3,366
  • 19
  • 21
  • It took me a bit longer to answer, but I think, you missed the point of single vs. double pointer :-) – Wolfgang Roth Feb 25 '20 at 07:40
  • Yes its working this way. But why it cannot be *b thats working..? – Preethi Feb 25 '20 at 07:48
  • @Preethi, because &b is giving a pointer to the adress of b, while *b is giving the content of the memory adress, that b is supposed to point to, but b is not a pointer at all. But c allows you to store pointers in any variable declaration when the memory for it is long enough (4 Byte with 32 bit pointers)... – Wolfgang Roth Feb 25 '20 at 08:04
  • i did not answer about pointer-to-pointer. Just saw the crash and focused on its fix. however 'b' was not initialized and that was the heart of misunderstanding. – eyalm Feb 25 '20 at 08:12
  • @WolfgangRoth Half understood from the comment ie., &b gives pointer to the address of b. So when I pass b, it is not a pointer to the address of b but it is a pointer to the value. pointer to a value is local to a function but pointer to an address is visible to the calling function as it points. Am I rite? – Preethi Feb 25 '20 at 08:24
  • @Preethi: phrases "pointer to a value" and "pointer to an address" are confusing. A pointer variable is still a value, it's a number, which represents an address in memory. If this address in memory is occupied by a static/global variable (i.e. long-lived variable), accessing it is defined throughout the program lifetime. However, if you are storing the address of an automatic variable (a local, non-static, stack based variable), then once the execution goes past the end of its enclosing block, this address doesn't contain a meaningful value and access it is undefined. – vgru Feb 25 '20 at 08:34
  • And keep in mind that all parameters in C are passed by value, i.e. passing a pointer to a function through a parameter creates a new temporary variable which contains this same address, but changing the temporary variable cannot affect the original variable. – vgru Feb 25 '20 at 08:36
  • If that is the case @Groo then `**ptr` is also a pointer to pointer variale whose scope is only nside the function.. I am trying to understand the diff between `*ptr` and `**ptr` as args where both are pointer to address but only double pointer works as expected.. – Preethi Feb 25 '20 at 08:54
  • When you write `ptr = (int *) malloc (sizeof(int))` inside `func2` (in your updated code), you pass the address returned by `malloc` to `ptr`. And `ptr` is a temporary variable as I wrote above. So once the function returns, you have a leaked block of memory allocated by `malloc`, but the original `b` variable is unchanged. – vgru Feb 25 '20 at 09:15
1

Maybe this helps a little:

int a=20, *pa=&a, **ppa=&pa;

var  mem       val
a   (0x1000)   20
pa  (0x2000)   0x1000
ppa (0x3000)   0x2000

ppa   == 0x2000
*ppa  == 0x1000
**ppa == 20

pa    == 0x1000
*pa   == 20
**pa  not possible

&a    == 0x1000
&pa   == 0x2000
&ppa  == 0x3000

If you call func2(pa) you call func2(0x1000). That's the location of a. So only a is changeable, not pa. If you call func(ppa) you call func(0x2000). That's the location of pa. So pa and a are changeable not ppa.

Holger
  • 899
  • 2
  • 7
  • 12
  • thanks for the response. I also know this is how a normal pointer works.. I am worried that unable to understand the argument concept. I am also working too hard to find it with what I know.. If a detailed answer is given, ill be thankful.. – Preethi Feb 25 '20 at 08:13
1

Let me put it in different way,

consider an example,

int x;
int *y = &x;
int **z = &y;
x = 10;

Which simplifies to this,

enter image description here

Note: Only for illustration purpose I have chosen address of x,y,z as 0x1000,0x2000,0x3000 respectively.


What is happening in func1?

ptr is local to func1, *ptr is same as accessing a and **ptr is same as accessing dynamically allocated memory. Dynamically allocated memory is stored to *ptr i.e to a.

What is happening in func2?

ptr is local to func2 and point to NULL on function call func2(b). On malloc, ptr will hold dynamically allocated memory but doesn't alter b. On exit of func2 scope memory is leaked(i.e lost the pointer to release the memory).

#include <stdio.h>
#include <stdlib.h>

void func(int **ptr)
{
    *ptr =  malloc (sizeof(int));
    **ptr = 10;
    printf("Inside func: ptr: %p *ptr: %p **ptr: %d\n", ptr, *ptr, **ptr);
}

void func2(int *ptr)
{
    int i = 10;
    ptr =  malloc (sizeof(int));
    *ptr = 288;
    printf("Inside func2: ptr: %p *ptr: %d\n", ptr, *ptr);
}

int main()
{
    int *a = NULL, *b = NULL;
    func(&a);
    printf("&a: %p, a: %p, *a: %d\n", &a, a, *a);
    func2(b);
    printf("b: %p\n", b);
    return 0;
}

output

Inside func: ptr: 0x7ffc75e14030 *ptr: 0x1db0010 **ptr: 10
&a: 0x7ffc75e14030, a: 0x1db0010, *a: 10
Inside func2: ptr: 0x1db0030 *ptr: 288
b: (nil)

Consider Do I cast the result of malloc? in your code.

TruthSeeker
  • 1,539
  • 11
  • 24
0

I try to give you a quick answer...

a single pointer declaration like void func2(int *ptr)will give you access to the memory location of whatever int value ptr is pointing to. but if you use void func(int **ptr) you give the adress of the pointer to the int variable.

You are using func2(b); without first assigning b (as it is a pointer to an int) a valid adress, something like this:

int an_integer = 13;
int *b = &an_integer;
func2(b); // now it should work
Wolfgang Roth
  • 451
  • 4
  • 18
  • Thanks for the response @wolfgang Roth. This means that, `ptr`'s value will hold an address to which the value is stored and the address's value can be accessed in `*ptr`. And in case of `**ptr`, there also I can get the access of `*ptr `only which now points to another address and that address has the variable. In both the ways only `*ptr` will help and changing `ptr` will affect only if I use double pointer - am i rite? – Preethi Feb 25 '20 at 07:57
  • no my main is this: ```int main() { int i = 11; int *a, *b = &i; func(&a); printf("&a: %p, a: %p, *a: %p *a: %p %d\n", &a, a, *a, *a); func2(&b); printf("*b: %d\n", *b); return 0; }``` still I am facing segfault – Preethi Feb 25 '20 at 07:59
  • @Preethi: `func2(&b)` should be `func(b)` if `b` is a pointer. – vgru Feb 25 '20 at 08:03
  • my main is this: ```int main() { int i = 11; int *a, *b = &i; func(&a); printf("&a: %p, a: %p, *a: %p *a: %p %d\n", &a, a, *a, *a); func2(b); printf("*b: %d\n", *b); return 0; }```, now am finding output as : ```Inside func2: ptr: 0xd93030 *ptr: 0x120 2084403040 *b: 11``` the `b`'s value remaining as it is. – Preethi Feb 25 '20 at 08:08
  • @Groo Thanks you for the suggestion, before i edit you posted :) – Preethi Feb 25 '20 at 08:09