Thread: adding a Node using a function...why is this happening?

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    53

    adding a Node using a function...why is this happening?

    I have run this code through the debugger and i can see the "menu->headInventory" get populated with the data from the "new" node. But as soon as it leaves the function the data stored in the "menu->headInventory" is no longer accessible, Im passing by reference so why is this occurring?

    Code:
     if ((validation = addNode(&menu, &lineBuffer, &new)) != TRUE) {
                fprintf(stderr, "Unable to add to node.\n");
                exit(EXIT_FAILURE);
            }
    Code:
    int addNode(HeadNode *menu, char *lineBuffer, InventoryTypePtr new) {
    
        char *tokens = NULL, delims[] = "|", type;
        int count = 1; /*case 1*/
    
        tokens = strtok(lineBuffer, delims);
    
        new = (InventoryTypePtr)malloc(sizeof(InventoryTypePtr));
        if (new == NULL) {
            fprintf(stderr, "Memory allocation for current failed");
            return FALSE;
        }
    
        /* Populate the node with the imported information from the
        line buffer */
        while (tokens != NULL) {
            printf("%s", tokens);
            switch (count) {
            case 1 :
                strcpy(new->inventoryID, tokens);
                break;
            case 2 :
                type = *tokens;
                new->foodType = type;
                break;
            case 3 :
                strcpy(new->inventoryName, tokens);
                break;
            case 4 :
                strcpy(new->inventoryDescription, tokens);
                break;
            }
            count++;
            tokens = strtok( NULL, delims);
        }
        new->nextInventory = menu->headInventory;
        menu->headInventory = new;
        menu->numInventoryNodes += 1;
        return TRUE;
    }

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by TonyG View Post
    Code:
        new = (InventoryTypePtr)malloc(sizeof(InventoryTypePtr));
    Because of it's name and the way you use it, I presume "InventoryTypePtr" was typedef'd this way:

    Code:
    typedef struct Inventory* InventoryTypePtr;
    IMO, typedefing pointers is not a good practice because it serves no purpose and could easily lead to confusion, but that's just my opinion.

    Anyway, since InventoryTypePtr is a pointer, how much memory do you think that malloc assigns? Throw this in:

    Code:
    printf("Size of InventoryTypePtr: %d\n", sizeof(InventoryTypePtr));
    I think you will find this does not jibe well with the actual size of the struct that a "InventoryTypePtr" points to.

    It seems, however, that you are getting off lucky; add a bit more to the program or compile it on another computer and this discrepancy will cause an access violation and seg fault, or -- even worse -- overwrite memory belonging to the program but not that variable, causing weirder and harder to solve problems.

    The reason your pointer is not populated outside that function is because you are reassigning the value of a value passed in. Look:

    Code:
    void example (int *x) {
          x = malloc(whatever);
    }
    Is exactly the same as:

    Code:
    void example (int x) {
          x = whatever;
    }
    Do you see now what is going on? Now consider:

    Code:
    void example (int *x) {
          *x = whatever;
    }
    Of those three examples, only the last one will affect the value of x in the caller. To assign memory to a passed in pointer and make it meaningful to the caller, you need to use a pointer to a pointer:

    Code:
    void example (int **x) {
           *x = malloc(sizeof(int));
           **x = whatever;
    }
    Last edited by MK27; 05-09-2011 at 06:36 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    May 2011
    Posts
    53
    Great i understand now. Thank you.
    Just one thing i would like to clear up. When using malloc. Would this be the correct way of writing it?

    Code:
    new = (InventoryTypePtr)malloc(sizeof(InventoryType));
     /* or better still */
    new = (InventoryType *)malloc(sizeof(InventoryType));
    Thanks heaps for the help.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    The closer one would be
    Code:
    new = (InventoryType *)malloc(sizeof(InventoryType));
    since it avoids typedef'ing pointers, which as MK27 pointed out, is confusing/problematic. But better yet, don't cast malloc.

  5. #5
    Registered User
    Join Date
    May 2011
    Posts
    53
    Quote Originally Posted by MK27 View Post
    Code:
    void example (int **x) {
           *x = malloc(sizeof(int));
           **x = whatever;
    }
    How do i use this pointer to a pointer. If it is a struct and i want to populate it as with my initial post?
    Code:
    strcpy(new->inventoryID, token);

  6. #6
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    You can make this easier to use like this:
    Code:
    void example (int **x) {
        int *local_x = malloc(sizeof(*local_x));
        /* Work with local_x, it's just a pointer now */
        
        /* Assign address of local_x to *x for return */
        *x = local_x;
    }

  7. #7
    Registered User
    Join Date
    May 2011
    Posts
    53
    Great thank you

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by TonyG View Post
    How do i use this pointer to a pointer. If it is a struct and i want to populate it as with my initial post?
    Code:
    strcpy(new->inventoryID, token);
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>    
    
    struct eg {
    	int x;
    	char data[256];
    };
    
    int create_eg (struct eg **new) {
    	*new = malloc(sizeof(struct eg));
    	if (!new) return -1;
    // dereferencing (*) a "pointer to a pointer" yields a normal pointer:
    	(*new)->x = 666;
    	strcpy((*new)->data, "hello world");  
    	return 0;
    }
    
    int main(void) {
    	struct eg *test;   // a pointer
    
    // the address of (&) a pointer is a pointer to a pointer:
    	create_eg(&test);    
    
    	printf("%d %s\n", test->x, test->data)
    
    	free(test);
    
    	return 0;
    }
    Last edited by MK27; 05-10-2011 at 04:44 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    May 2011
    Posts
    53
    Thanks guys. Managed to get both approaches to work. For readability i have used the second. But both were effect and solutions to my problem.

  10. #10
    Registered User
    Join Date
    May 2011
    Posts
    53
    Still having trouble understanding passing a struct as a pointer "call by reference".

    menu has been declared as a HeadNode struct
    Code:
    typedef struct head
    {
       InventoryTypePtr headInventory;
       unsigned numInv;
    } HeadNode;
    an instance of HeadNode is declared in my Main as
    Code:
     HeadNode menu;
    menu is being passed through functions as a pointer

    Code:
    addNode(&menu, ....);
    Code:
    addNode(*menu, ...);
    From the above examples i have the information stored in headInventory and headInventory's follow on nodes.
    But if i try and set the value of numInv = 0 in a function. Once it leaves the function the value of numInv is set to <large rand num>.

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You can't have both "addNode(&menu, ....);" and "addNode(*menu, ...);" at the same time. The first would be correct.

  12. #12
    Registered User
    Join Date
    May 2011
    Posts
    53
    sorry didn't make the second very clear should have been

    Code:
    addNode(*menu, ...) {
    menu->numInv = 0;
    }

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Your idea of snippet is lacking. Complete example, please.

  14. #14
    Registered User
    Join Date
    May 2011
    Posts
    53
    in the header
    Code:
    typedef struct head
    {
       InventoryTypePtr headInventory;
       unsigned numInv;
    } HeadNode;
    Code:
    int main(int argc, char* argv[]) {
    
        HeadNode menu;
        systemInit(&menu);
        printf("menu.num = %u", menu.numInv);
    Code:
    void systemInit(HeadNode* menu) {
    menu->numInv = 0;
    }
    Output is some over sized number stored in numInv...

  15. #15
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Hi Tony... You really need to give us more than 2 and 3 line examples here... Post your code... or at least post complete functions.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Adding a node to linked list
    By laurenlb in forum C Programming
    Replies: 1
    Last Post: 04-14-2011, 07:05 PM
  2. Adding a new node to linkded list
    By OCcounty in forum C Programming
    Replies: 23
    Last Post: 07-27-2010, 04:06 PM
  3. Adding a node of struct
    By zyphirr in forum C Programming
    Replies: 1
    Last Post: 12-03-2008, 06:08 PM
  4. Adding a node to a linked list
    By slopeski007 in forum C Programming
    Replies: 2
    Last Post: 02-02-2003, 12:31 AM
  5. Adding Node - Double Linked List
    By SeanMSimonsen in forum C++ Programming
    Replies: 3
    Last Post: 11-10-2002, 12:43 PM