简体   繁体   中英

malloc memory to a pointer to pointer

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

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

You want to change the pointer, ie, 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.

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!
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM