Me_me_me
Me_me_me

Reputation: 124

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);
}

Upvotes: 4

Views: 5146

Answers (5)

Vlad from Moscow
Vlad from Moscow

Reputation: 310950

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 );

Upvotes: 8

kos
kos

Reputation: 876

Why do i need a double pointer for that?

This is what i understand your question is. The answer is: because like all actual parameters (wich are copies of the value passed by the caller), pointers passed to a function will hold their values in the scope in which they have been actually declared (which in this case is the called function's scope), without changing anything in the caller function. And this is not what you want, because you want to change the value of w.

If you do something like that:

void MyFunction(int* p) {
    //`p`'s value, like `a`'s value, is NULL
    *p=(char *)malloc(256*sizeof(char));
    //`p`'s value is the starting address of the buffer, but `a` didn't change
    return;
}

int main() {
    char* a;
    a=NULL;
    MyFunction(a);
    return 0;
    //`a`'s value is still NULL, because MyFunction() changed only its own copy of `a`
}

Nothing happens, because you just change the address pointed by p inside MyFunction().

So, as you would do for integers:

void MyFunction(int* p) {
    *p=1;
    return;
}

int main() {
    int a;
    a=0;
    MyFunction(&a);
    printf("%d", a);
    return 0;
}

do the same for pointers:

void MyFunction(int** p) {
    *p=(char *)malloc(256*sizeof(char));
    return;
}

int main() {
    char* a;
    a=NULL;
    MyFunction(&a);
    return 0;
}

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).

Look at your code:

wpisuj(&w);

The amperstand here dereferences the pointer w. This means that the whole expression &w has the value of the address of w. So what you're passing is the address of a pointer to a char variable, which is a pointer to a pointer to a char variable. Which is correct: if you need to change an integer, you pass the address of the integer. If you need to change a pointer, you pass the address of the pointer. And therefore it's even correct to use wpisuj(char** 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.

Because you're not placing a string: if w (inside wpisuj()) like said before is a pointer to a pointer to a char, *w (inside wpisuk()) is a pointer to char, which is the equivalent of *(&w) in main() which is the value of w in main(). So what you're doing is you're assigning the value returned by malloc() to your pointer w in main().

Upvotes: 0

user3386109
user3386109

Reputation: 34829

The code below shows a different way to do the same thing. The major difference is the wpisuj function returns the pointer to the newly allocated string (which main then assigns to w). This technique avoids the use of a pointer-to-a-pointer since wpisuj doesn't need to modify main's copy of w.

Other differences

  • error checking: return values from scanf and malloc are checked
  • no memory leaks: free( w ) at the end
  • better security: %255s in scanf prevents the user from overflowing the buffer

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

char *wpisuj( void )
{
    char bufor[256];

    if ( scanf( "%255s", bufor ) != 1 )
        return( NULL );

    char *w = malloc( strlen(bufor) + 1 );

    if ( w != NULL )
        strcpy( w, bufor );

    return( w );
}

int main()
{
    char *w;

    if ( (w = wpisuj()) != NULL )
    {
        printf( "%s\n", w );
        free( w );
    }

    return 0;
}

Upvotes: 0

delirium
delirium

Reputation: 918

Well, I'll explain what I understood of your question: Whenever you want to use a function to change your variable you need to send its address, otherwise inside your function you'll change a local copy (local for the function) and, once it returns, it will be lost.

1) Basically, in your main, you create a pointer that points to nothing and you call the function wpisuj() to make it point to something. Using the above idea, you must send the memory position of your pointer, so the function can change where it points to. If you sent just w instead of &w you would be sending a copy of the address to where it points and wouldn't be able to change it.

2) Your function strcpy expects a certain input which is the address of the string and not the address of you pointer. Hence, you use *w to get where your w is pointing to.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206567

The reason wpisuj is passed a char** is that when memory is allocated in the function and assigned to *w, the change is visible in the calling function when you return from wpisuj.

If you had:

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

The change to w is only a local change. The calling function does not see the change.

Upvotes: 4

Related Questions