Home > Blockchain >  When is it valid to pass a pointer out of a function?
When is it valid to pass a pointer out of a function?

Time:11-26

I'm wrestling with the minutiae of variable lifetimes in C (of course)!

I've learnt that I shouldn't leave variables that were defined within functions floating around, expect when the memory for that variable has been allocated with malloc. What I can't work out is how I know when a pointer is good to pass out of a function.

In the following example, there is a fundamental difference between fptr and p_uniqueId:

int initialize_db(ToyDatabase* p_tdb, const char* filePath) {
    
    FILE* fptr;
    if ((fptr = fopen(filePath, "wb")) == NULL) {
        printf("Error! opening file");
        return -1;
    }
    int uniqueId = 2;
    int* p_uniqueId = &uniqueId; 
    p_tdb->pFile = fptr;  //Presumably not a dangling pointer, how to tell?
    p_tdb->pId = p_uniqueId; //Will become a dangling pointer, not Ok!
    return 0;
}

int cleanup(ToyDatabase* p_tdb)
{
    fclose(p_tdb->fptr);
    //Do I need to do anything else with this fptr? Maybe p_tdb->fptr = NULL;????

    return 0;
}

In the example, the address pointed to by p_tdb->pId won't be valid outside the initialize_db function. But presumably p_tdb->pFile will be valid, presumably because fopen allocated memory for fptr.

Is there something in the documentation for fopen that I'm looking for that delineates these two cases, or is it just assumed that any function returning a pointer has been mallocd?

CodePudding user response:

First, p_uniqueId unambiguously points to uniqueId which has automatic storage class. If it were a global, malloc'd, static, etc then you'd be fine.

Is there something in the documentation for fopen that I'm looking for that delineates these two cases, or is it just assumed that any function returning a pointer has been mallocd?

The manpage doesn't say much. It just says that a FILE* is returned, which you can safely use and pass around. It might not have been necessarily malloc'd, as it could have been allocated in a static buffer or other implementation-dependent storage. You thus can't assume that it can be safely freed. At best you leave a dangling file descriptor because free doesn't know anything about file streams.

The only remarks about cleanup that I found were in the fclose manpage:

[after calling fclose]... any further access (including another call to fclose()) to the stream results in undefined behavior.

//Do I need to do anything else with this fptr? Maybe p_tdb->fptr = NULL;????

You don't need to do anything, per se. You can leave p_tdb->fptr dangling with the understanding that using it is UB. You could null it. You could replace it with a different file pointer. By setting it to NULL, you can detect that it doesn't point anywhere meaningful using a null-check. If you don't check it, it's just as harmful to use (UB wise) after being nulled as if you used it while it was dangling.

  •  Tags:  
  • c
  • Related