简体   繁体   中英

pointer parameter corrupted: returning the pointer or passing address of pointer works

I'm passing a pointer to a user-defined type to a function that malloc 's memory and sets this pointer to point to it. malloc() comes back with a pointer, but when I return from the function, my pointer is clobbered. I came up with a couple of fixes:

  • return the pointer instead of passing it
  • pass the address of the pointer rather than the pointer itself

I suspect this is akin to the case with FILE pointers; if you pass the pointer to a function, you can't count on the pointer not being changed because the system may fiddle with it. So you pass the address of the FILE * instead.

Anyone have an explanation for this? Here's the code (sorry, it's a bit long):

typedef struct  {
    BOOK *bookAry;
    int numBooks;
}INVENTORY;

I had this in main() , where INVENTORY is a user-defined type as above:

//variable declarations
INVENTORY *inv = NULL;

//process
initInventory( inv, bookArySize );
processFile( inv );

The initInventory() function is as follows:

void initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
       //more code here....
    return;

}//initInventory

So we return to main() (we think) with inv pointing to the newly-allocated memory (and inv points to a struct that has other pointers). Only when I pass the pointer inv to processFile() , it's been clobbered, and when I try to reference the data in the inventory struct, I get an access violation. It turns out the pointer's invalid on return to main() !

This fixed it: main() has:

//variable declarations
INVENTORY *inv = NULL;

//process
inv = initInventory( inv, bookArySize );
processFile( inv );

and initInventory() is changed to this:

INVENTORY * initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );


    //return a pointer to the INVENTORY header struct
    return inv;

}//initInventory

Then I tried this, which I think is a better fix. main() now has:

//variable declarations
INVENTORY *inv = NULL;
    //more code here...

//process
initInventory( &inv, bookArySize );
processFile( inv );

And initInventory() is as follows:

void initInventory( INVENTORY **inv, int size ) {

    //process
    *inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
        //more code here....
    return;

}//initInventory

What you do here:

void initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
    //more code here....
    return;

}//initInventory

is basically this: You pass a copy of the address as a parameter and then change the copy. It has the same affect as assigning something to size inside that function: It just changes the local copy.

Your "fixes" are the two correct solutions: Either pass in a pointer to the variable which you want to change (and in this case it's a pointer to a pointer) or return the pointer of the malloc.

btw: You should not cast the return value of malloc. You gain nothing and hide potential problems. See also this question .

Basically, if you pass in a pointer by value, it is copied into the parameter and the caller pointer cannot be changed by the called function - the malloc() assigns to the passed parameter OK, but this change to the copy is lost upon return from the function - *INV remains NULL. Explicitly returning the pointer, or passing in the pointer by reference, (**), are both fine - the pointer returned by malloc() is loaded into the callers variable and so can be successfully dereferenced by the caller after the return.

It is the same issue as FILE pointers. If you intend to open the file inside the called function and access it in the caller after return, you cannot pass in the FILE* by value.

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