Search code examples
cfunctionpointerspass-by-referencepass-by-value

Why 2 stars when passing pointer to a string to a function


After a long time spent on making this code work, can someone explain to me why I need 2 stars when I pass a pointer to a string as an argument to the function? A pointer, by definition, keeps the address to a memory where a certain variable will be placed. So it is a variable that has got its own address and under this address is address to another variable. Okay. So if I pass a pointer to a function I use ampersand because I must pass the pointer address to the function. Fine. But then what happens. The function receives the information where in the memory is located this pointer. Okay. This is what I understand. What I do not understand is why I need two stars when I define the function and its argument. I am passing a pointer to a char variable. Why not void wpisuj(char * w). Why wpisuj(char** w). Memory allocation is understandeable to me - I reserved memory with malloc and malloc returns address of this memory, so I place this address as the value of the variable w. And then again something I do not understand, if *w is the pointer and keeps the address of the newly created place in the memory, why I use *w to place there a string. Should it not be *(*w)? Since *w is the address of the reserved memory, then *(*w) is the contents of this memory.

Summing up. What I do not understand is: 1) why wpisuj (char **w) instead of wpisuj (char *w) 2) why strcpy(w, bufor) instead of strcpy((*w), bufor)

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
# define SIZE 256

void wpisuj(char** pw){
  char bufor[256];
  scanf("%s", bufor);
  int l;
  l=strlen(bufor)+1;
  *pw=(char*)malloc(l*sizeof(char));
  strcpy(*pw, bufor);
}


int main(){
  char* w;
  wpisuj(&w);
  printf("%s", w);  

   return 0;
}

And if I may also ask about freeing the memory. Am I correct in thinking that this is the corect amount of stars (as in the code below):

void free_memory(char **w){
   free(*w);
}

but, if I freed memory in main() I would have:

int main(){
  w=malloc(sizeof(buffer)+sizeof(char));
/* some code before */
  free(w);
}

Solution

  • To make it clear consider the following simple program

    #include <stdio.h>
    
    void f( int x )
    {
        x = x + 20;
    }
    
    int main(void) 
    {
        int x = 10;
    
        printf( "Before the call f( x ) x = %d\n", x );
        
        f( x );
        
        printf( "After  the call f( x ) x = %d\n", x );
        
        return 0;
    }
    

    The output will be

    Before the call f( x ) x = 10
    After  the call f( x ) x = 10
    

    As you see x was not changed in the function f because the function deals with a copy of the value of the object x defined in main.

    However if you will rewrite the function the following way

    #include <stdio.h>
    
    void f( int *x )
    {
        *x = *x + 20;
    }
    
    int main(void) 
    {
        int x = 10;
    
        printf( "Before the call f( x ) x = %d\n", x );
        
        f( &x );
        
        printf( "After  the call f( x ) x = %d\n", x );
        
        return 0;
    }
    

    then in this case the output will be

    Before the call f( x ) x = 10
    After  the call f( x ) x = 30
    

    because we passed to the function the address of the original object x and inside the function the original object itself was changed due to dereferencing the passed pointer.

    The same is valid with the pointer from your post.

    If you will define a pointer

    char *p;
    

    in main and pass it as an argument to function

    void f( char *p );
    

    then the function will deal with a copy of the original object (pointer). Any changes of the copy do not influence on the original pointer. So as in the first example you should pass a pointer to this pointer that is the function should be declared like

    void f( char **p );
    

    and you have to call it like

    f( &p );