Thread: variable scope - how to initialize variable in external function

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

    variable scope - how to initialize variable in external function

    Hi all,

    I am writing a program that uses XPath to search an XML document. There are several sanity checks that need to be performed before performing the search. To clean up the function, I am trying to put the sanity checks in a separate function. The problem is that this entails initializing the strucutures in the external function. I have come to realize that, even though they are pointers, if they are initialized in the external function, their value is not kept once they return to the main fucntion.
    I have created a simple example to illustrate the point. In the following program, I define a "book" structure with 3 properties. In main(), I declare two "book" variables, one is initialized within main(), the other is initialized in an external function. The one that is initialized in the external function is no longer valid once it returns to main(). Can anyone suggest how to address this problem?



    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct {
        int npages ;
        char* color ;
        int isbn ;
    } book ;
    
    int set_isbn(book* elbook, book* elbook2) {
        elbook->isbn = 1234 ;
    
        elbook2 = malloc(sizeof(book)) ;
        elbook2->isbn = 789 ;
        elbook2->color = "brown " ;
        elbook2->npages = 5 ;
    
        printf("The book has %d pages, its %s, and its isbn is %d\n", elbook2->npages, elbook2->color, elbook2->isbn) ;
    
        return 0 ;
    
    }
    
    int main()
    {
        book* thebook = malloc(sizeof(book)) ;
        book* thebook2 = NULL ;
        thebook->color = "white" ;
        thebook->npages = 4 ;
    
        set_isbn(thebook , thebook2) ;
        printf("The book has %d pages, its %s, and its isbn is %d\n", thebook->npages, thebook->color, thebook->isbn) ;
        printf("The book has %d pages, its %s, and its isbn is %d\n", thebook2->npages, thebook2->color, thebook2->isbn) $
        return 0 ;
    }
    The output:

    Code:
    The book has 5 pages, its brown , and its isbn is 789
    The book has 4 pages, its white, and its isbn is 1234
    zsh: segmentation fault  ./a.out
    The segfault is due to trying to access the memory location of thebook2, which is no longer valid.




    Thanks,

    JD

  2. #2
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    You have to pass elbook2 by reference
    e.g.
    Code:
    int set_isbn(book* elbook, book** elbook2) {
        elbook->isbn = 1234 ;
    
        *elbook2 = malloc(sizeof(book)) ;
        (*elbook2)->isbn = 789 ;
        (*elbook2)->color = "brown " ;
        (*elbook2)->npages = 5 ;
    
        printf("The book has %d pages, its %s, and its isbn is %d\n", (*elbook2)->npages, (*elbook2)->color, (*elbook2)->isbn) ;
    
        return 0 ;
    
    }
    call it this way
    Code:
    set_isbn(thebook , &thebook2) ;
    Kurt

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I'd call it by address or pointer. Anyway, I am wondering, do you need malloc here? Or perhaps this is just a dumbed down examples and you really need it in your real code?
    Oh, and as for the why, consider that the pointer's value is copied over to the function, so the elbook2 inside the function is a copy of the original variable in main. This is why we use pointers in the first place. So you just have to pass the pointer by pointer. Thus the type the pointer should point to is elbook*. The rest is easy, right?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Feb 2010
    Posts
    5
    Thanks Kurt! That works fine. I don't really understand why though. I don't expect to ever really know all the intricacies of C, but I guess I can try. Is there a simple explanation?
    My understanding was that when you pass a variable, that is a pointer, to a function, you are passing the pointer to the address of the variable to the function. So within that function, you are modifying the same pointer.

    So was my problem related to the scope of variable assignments within functions (i.e. after the function exits, it deallocates the value it allocated using malloc)?


    Thanks,

    JD

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A variable is a storage place. That storage place is in the computer memory.
    Now, remember this: everything in C is passed by value. Everything. So every variable you pass to a function, a copy is made and its value copied over.
    Therefore, each function has a local copy of the variables, with the same value. So changing them won't change the original variables in the calling function.
    To get around this, we tell the function where in memory the variables we want to change are stored. These addresses are stored in pointers. So a pointer's value is a memory address to a certain type. Naturally, this address, this value, is copied over to the function when you pass them in as arguments. So the function gets a local pointer variable with the original memory address.
    So, naturally, if you want to change the actual pointer's value, you need to pass the pointer's address, since they are also variables, and thus also stored in memory.
    Makes sense?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User
    Join Date
    Feb 2010
    Posts
    5
    Elysia,

    Oops, I posted before seeing your reply above, I'll read it now...


    In the actual code, the actual object is allocated by calling another function.

    Something like this:

    Code:
    int function(xmlXpathObject** xpathObj)
    {
    ...
    *xpathObj = xmlXPathEvalExpression(*xpathExpr, *xpathCtx);
    if(*xpathObj == NULL) {
      handle_problem()
      return(-1)
    } 
    return(0)
    }
    ...
    
    int main()
    {
     xmlXPathObject* xpathObj = NULL ;
     if( function(&xpathObj) != 0) {
       print_error()
     }
     else {
      proceed()
     }
    }
    I'm trying to keep all the error checking out of the main() function.



    Thanks,

    JD
    Last edited by jzanow; 02-14-2010 at 04:01 PM. Reason: hadn't read response

  7. #7
    Registered User
    Join Date
    Feb 2010
    Posts
    5
    In regards to Post #5...

    Ah, I think I see what I was doing wrong here. Originally, I was passing the value of the pointer to this function. But since the variable was declared as NULL, there really was no valid address assigned to it. The address is assigned during malloc(). Since I had passed the value of the (undeclared) pointer, that is what I was trying to access in the printf() function in main() after calling the set_isbn() function.
    Last edited by jzanow; 02-14-2010 at 04:07 PM. Reason: grammar

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Simply put, the value of the pointer in main doesn't change because you assign malloc to the local pointer in the function. So yes, it would try to access NULL.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Feb 2010
    Posts
    5
    Got it. Thanks!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  2. <Gulp>
    By kryptkat in forum Windows Programming
    Replies: 7
    Last Post: 01-14-2006, 01:03 PM
  3. Replies: 5
    Last Post: 01-13-2006, 12:00 AM
  4. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  5. debug to release modes
    By DavidP in forum Game Programming
    Replies: 5
    Last Post: 03-20-2003, 03:01 PM