Thread: Passing by reference of by value?

  1. #1
    Registered User
    Join Date
    Jan 2010
    Posts
    5

    Passing by reference of by value?

    Hi I have a "myfree" function which frees my pointer allocated memory space, but after freeing my pointers and make them NULL, when the functions returns to main the pointer address (although already free) it still points to the previous address?

    can someone explain me why this is happening, it seems to me like a problem of "passing by value" but I'm "passing by reference" to avoid this issues isn't it?
    Code:
    #include<stdio.h>
    #include<stdlib.h>
    
    typedef struct S1{
      int a;
      char b;
    }S1;
    
    void myfree(void* freeptr)
    {
    
      if (!freeptr){
        return;
      }
    
      printf("%s-About to free %p\n",__func__,freeptr);
      free(freeptr);
      freeptr = NULL;  # this line do not do what I want when it returns to main
      printf("%s-Freed %p\n",__func__,freeptr);
      
    
    }
    int main()
    {
      S1 *ps1 = NULL;
      ps1 = malloc(sizeof(S1));                                                                                                                      
    
      printf("%s-About to free %p\n",__func__,ps1);
      myfree(ps1);
      printf("%s-Freed %p\n",__func__,ps1);
    
      return 0;
    }
    And this the output of the program:

    main-About to free 0x9cdf378
    myfree-About to free 0x9cdf378
    myfree-Freed (nil)
    main-Freed 0x9cdf378 <--------- I was expecting this to be NULL ?!?!?!?!

    Thanks for your help!
    Last edited by Salem; 01-27-2010 at 10:37 AM. Reason: Added code tags - learn to use them yourself

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Well no, because you're only setting the local copy of the pointer to NULL.

    > it seems to me like a problem of "passing by value" but I'm "passing by reference"
    Yes, you need to pass a reference to "the pointer itself".

    That means another * in your function declaration, and calling
    myfree( &ptr );
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2010
    Posts
    5
    I see.... I thought I was already "passing by reference" by just passing a pointer but indeed I need to pass a reference to the pointer in self...

    So I think basically passing a pointer as argument doesn't always implies you are "passing by reference"....

    I just tried your suggestion and it worked fine!

    Thanks!

  4. #4
    Registered User
    Join Date
    Jan 2010
    Posts
    5
    PS: Also it's was a really subtle error because I was able to free the pointer successfully but not change it's address to NUL.....

  5. #5
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Wait so, at the risk of looking retarded...that code only works if what? You changed your function to accept void** freeptr and then in main called "myfree(&ptr)"?

    Friggin pointers.

  6. #6
    Registered User
    Join Date
    Jan 2010
    Posts
    5
    This is how I get it working:

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

    typedef struct S1{
    int a;
    char b;
    }S1;
    void myfree(void** freeptr)
    {

    if (!*freeptr){
    printf("No need to free %p\n",*freeptr);
    return;
    }

    printf("%s-About to free %p\n",__func__,*freeptr);
    free(*freeptr);
    *freeptr = NULL;
    printf("%s-Freed %p\n",__func__,*freeptr);

    }


    int main()
    {

    S1 *ps1 = NULL;
    ps1 = malloc(sizeof(S1));

    printf("%s-About to free %p\n",__func__,ps1);
    myfree((void**)&ps1);
    printf("%s-Freed %p\n",__func__,ps1);

    return 0;
    }


    And the output is:
    main-About to free 0x95e7378
    myfree-About to free 0x95e7378
    myfree-Freed (nil)
    main-Freed (nil)

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Read about code tags. Your first fix was free.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I would recommend re-thinking this approach. The only way that your program is portable is if you only use void* pointers. The way you have it--casting to void**--is not guaranteed to work. If pointers have different sizes/representations, things will go haywire. Generally speaking, when you have to cast, a different approach should be considered (not all casts are bad, of course, but they tend to be used more often than they should).

    To be properly generic I'd recommend a macro, such as:
    Code:
    #define MYFREE(p) do { free(p); p = NULL; } while(0)
    It requires an lvalue, but so does the & operator (except for a couple of cases that really don't matter here). The macro version doesn't care what pointer type p is. As long as it's an object pointer, it will work. free(NULL) is valid, too, so unless you want to alert the user to such usage, there's no need for a check before you call free().

  9. #9
    Registered User
    Join Date
    Jan 2010
    Posts
    5
    actually I'm building a shared library in which I wanted to use "myfree" function and I'm calling it for a different number of, as you said, sizes/representations so I think I'll follow your suggestion... besides your macro looks more elegant!

    by the way I've never understood that "do{...}while(0)" structure on macros? any comments on that?

    Thanks

  10. #10
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    by the way I've never understood that "do{...}while(0)" structure on macros? any comments on that?
    Doing it that way creates an expression but not a statement, which can be useful for a case like:
    Code:
    if(blah) MYFREE(p);
    else something;
    If you were to just use { } to surround the code, that would come out to:
    Code:
    if(blah) { free(p); p = NULL; };
    else something;
    Note the semicolon: that's a problem! With the do/while method, a semicolon works just fine (and is what you would expect to do).

  11. #11
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    I don't disagree with the solution, but is there a chance of void** not having the same size of any other pointer? All pointers should have the same size since they hold memory addresses

  12. #12
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    is there a chance of void** not having the same size of any other pointer?
    Yes. While modern systems tend to have all pointers as the same size/representation, there's no requirement for them to be so. The original solution will probably work, but when there's a solution that's more portable, I would recommend using it.

    That said, this is one of the areas that you're probably not going to get burned on if you violate the standard. But hey, why take chances?

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > All pointers should have the same size since they hold memory addresses
    Question 5.17
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Quote Originally Posted by Salem View Post
    > All pointers should have the same size since they hold memory addresses
    Question 5.17
    Does that actually apply to modern computers though?

  15. #15
    Registered User
    Join Date
    Jan 2010
    Posts
    412
    From the C99 standard
    6.3.2.3 Pointers
    A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
    It doesn't specifically say a void pointer has to be the same size as any other pointer, but it says that you can convert back and forth so implicitly they have to be the same size.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM