1

I have came across this problem when using pointer to pointer to a char:

void setmemory(char** p, int num)
{
    *p=(char*)malloc(num);
}

    void test(void)
    {
        char* str=NULL;
        setmemory(&str,100);
        strcpy(str,"hello");
        printf(str);
    }

int main()
{
    test();
    return 0;
}

The code above is correct,but I can't figure it out why using a pointer to a pointer char** p here? Why just using a pointer to a char instead? so I change this snippet into below and found it not working ,can anyone tell me why? thanks!

void setmemory(char* p, int num)
{
    p=(char*)malloc(num);
}

void test(void)
{
    char* str=NULL;
    setmemory(str,100);
    strcpy(str,"hello");
    printf(str);
}

int main()
{
    test();
    return 0;
}
3
  • 5
    c-faq.com/ptrs/passptrinit.html Commented Apr 18, 2012 at 13:39
  • p is a local variable. *p is not. Commented Apr 18, 2012 at 13:44
  • @cnicutar,nice example here ,thank you! Commented Apr 18, 2012 at 14:23

4 Answers 4

3

One thing to note here is - When we say pointers, we generally tend to think in terms of pass by reference but not necessarily. Even pointers can be passed by value

char* str is local to test and char* p is local to setmemory . So the changes you do in setmemory will not be visible in test if you dont send a pointer to a pointer.

You can make it work with a single pointer like this

 char * setmemory(char* p, int num) // p is a new pointer but points at the same
                                    // location as str
{
    p=(char*)malloc(num); // Now, 'p' starts pointing at a different location than 'str'
    strcpy(p ,"hello");  // Copy some data to the locn 'p' is pointing to
    return p; // Oops. The poor `str` is still pointing at NULL :( 
              // Send him the address of the newly allocated area
}

void test(void)
{
    char* str=NULL;
    str=setmemory(str,100); // We are passing a pointer which is pointing to NULL

    printf(str); //Now str points to the alloced memory and is happy :)
}

int main()
{
    test();
    return 0;
}

Note that in setmemory we are returning a local pointer, but it is not a problem ( no dangling pointer problems ) as this pointer points to a location on heap and not on stack

Sign up to request clarification or add additional context in comments.

4 Comments

Got it!Thank you very much,pavan!It's a very interesting and detailed explanation^_^
@worldpeace Do remember to accept one of the answers that helped you by checking the tick mark next to every answer
Sorry, another quick newb question, why is "free" not necessary here? I thought free was always needed if malloc is used?
@PeteHerbertPenito Yes. It is a good programming practise to free all malloced memory once done. But this example was dealing with some other concept and the code is just for illustration . Hence no focus on free.
0

You want to change the pointer, i.e., the function need a reference, not a value. In C, this is done by giving the address (pointer) to the variable that is by change a pointer itsself. Thus, one pointer is for referencing, the other for you porgram logic.

Comments

0

You are only setting the local variable *p here. Remember you are getting a pointer to data, not a pointer-to-pointer-to-data.

Think of it like this:

First case:

int a;

foo(a); // Passes a
void foo(int b)
{
  b = 4;    // This only changes local variable, has no effect really
}

Second case:

int a;
foo(&a); // Passes *a

void foo(int *b)
{
  *b = 4; // This changes the contents of a. As you can see we have not changed the original pointer!
  b = 4; // This changes our local copy of the pointer, not the pointer itself, like in the first case!
}

Third case

int *ptr;
foo(&ptr); // Passes **ptr

void foo(int **b)
{
  **b = 4; // This changes the data of the passed pointer
  *b = 4; // This changes the passed pointer itself, i.e. it changes ptr. This is what test() is doing, the behavior you are looking for!
  b = 4; // This changes our local copy of a variable, just like the first case!
}

Comments

0

The orignal code is passing in the location of where the caller wants the string pointer put. If you pass in only a 'char*', the caller will pass by value the contents of the callers location - probably some uninitialized value.

If the callee has to return a string, or other indirected struct, you need both asterisks so that the callee can return a pointer into the callers pointer variable.

Does that make sense? It did to me, but then again, I wrote it.

1 Comment

thank you for your time and code here!I appreciate it very much^_^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.