Thread: Dynamically allocated array of pointers to structs

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    5

    Dynamically allocated array of pointers to structs

    I'd appreciate some help from anyone who can give it. I'm trying to set up a menu hierarchy with arrays of pointers to the struct. Right now it seems to be working partially, but I'm getting some weird results from the function.

    3-4 of my 7 menus print out in correct fashion up until where they start to overlap.

    I tested initializing several menus declared similarly to searchNameMenu below and testing the value of the memory addMenu has after the realloc and it tends to (seemingly) randomly be assigned a memory block from a previous array initialization. Why is this? I've already found out that I can't use sizeof on dynamically allocated arrays... am I using realloc on the array incorrectly?

    Code:
    typedef struct MenuStruct
    {
        char question[100];
        void (*menuCommand) ();
        struct menuStruct *nextMenu;
    }menuStruct; //end menuStruct
    typedef menuStruct *menuStructPtr;
    
    
    menuStructPtr searchNameMenu[0];
    
    
    void initSearchNameMenu()
    {
        int i = 0;
        addMenuItem(searchNameMenu, "Search names by name.", NULL, &i);
        addMenuItem(searchNameMenu, "Search names by length.", NULL, &i);
        addMenuItem(searchNameMenu, "Search names by percentage.", NULL, &i);
        addMenuItem(searchNameMenu, "Return to Previous Menu.", NULL, &i);
        addMenuItem(searchNameMenu, "Return to Main Menu.", NULL, &i);
    } //end function initSearchNameDBMenu
    Function in question:

    Code:
    void addMenuItem(menuStructPtr addMenu[], char question[], menuStructPtr nextMenu[], int *i)
    {
          menuStructPtr newOption;
    
          newOption = (menuStructPtr)malloc(sizeof(menuStruct));
          strncpy(newOption->question, question, 100);
          //newOption->nextMenu = nextMenu; this is used in my larger program
    
          addMenu = (menuStructPtr*)realloc(addMenu, ((*i+1) * sizeof(newOption)));
          if(addMenu == NULL)
            printf("Oh noes, not enough mem");
    
          //printf("%d\n", addMenu);  this is what I used to test the memory being assigned
    
          addMenu[*i] = newOption;
          (*i)++;
    } //end function addMenuItem
    I tried to cut the code down as much as possible, I think this should be enough; as far as I know the error is in this function. If you would need to see code more to help, I can definitely provide it.
    Last edited by Roguefeebo; 04-30-2007 at 07:42 AM.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I don't understand why you are doing 99% of what you are doing. All you have to do is allocate a new menu item structure and link it onto the linked list. And why are you declaring the head of the list as a zero-length array? Very weird.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    5
    Well, I'm trying it out mostly for practice. This is an extension of a homework assignment from last semester that I'm doing for my own practice. I've never used dynamic arrays or void pointers and I figured this would be a non-trivial enough program to get used to how they work.

    As for the program, I also have it set up later to display the menu options (a, b, c, etc) for the array based on the index value and then perform a function (or go to the next menu) in the array based on an input that would be applied to the index of that array.

    I know an alternate (and somewhat easier) way to do it would just be a chain of new menu structs, but I know it should work this way too.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Roguefeebo View Post
    I know an alternate (and somewhat easier) way to do it would just be a chain of new menu structs, but I know it should work this way too.
    You should just have a single pointer to the dynamic array. Don't declare it as a [0] array, it's just a pointer. You need another variable which keeps track of how big the array is. When you add an element to it, realloc() it to expand its size by one struct and update the size variable appropriately. Then copy the menu item into this new position.

    Why is there a next pointer if it's not a linked list?

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    5
    Code:
    void displayMenu(menuStructPtr menuArr[])
    {
    int i = 0;
    
    while(menuArr[i] != NULL)
    {
     printf("%c.  %s\n", (i+97), menuArr[i]->question);
     i++;
    }
    } //end function displayMenu
    
    
    
    int menu(menuStructPtr menuArr[])
    {
      int exit = 0;
      char choice;
    
      while(exit == 0)
      {
        displayMenu(menuArr);
        scanf("%c", choice);
        choice = tolower(choice);
    
        if(menuArr[choice-97] != NULL)
          if(menuArr[choice-97]->nextMenu != NULL){}
            //exit = menu(menuArr[choice-97]->nextMenu);
          else
          menuArr[choice-97]->menuCommand;
        else
        printf("Incorrect option chosen");
    
      if(exit == -1)
        return -1;
      if(exit == 1)
        return 0;
    } //end while
    
    return exit;
    } //end function menu
    A couple other functions that I haven't been able to debug yet because I can't get past my menu display issue atm (so be soft on the bugs pls, :P). The menu function *should* start up the nextMenu array (that's why it's a pointer) if that particular menu option is chosen within the hierarchy.

    I just declared the arrays as [0] to try to designate that they were going to be handled as dynamic arrays later on. The functionality should be the same, I was just trying to make it a little more clear in the way they would be handled. It compiled either way, but that's not saying I'm handling them correctly later on. The display function works, the first few menus print out perfectly. I can see through debugging that the new menu items are being assigned the same memory block of previous arrays within the addMenuItem function.

    Right now I'm trying to do a malloc on the struct, assign the address of that struct to a pointer and then realloc the array by the size of that pointer to assign the pointer only.

    Do you think it's too complicated to be helpful in learning about these kinds of things? Will I never have a need to use these things similar to the way I'm using them?
    Last edited by Roguefeebo; 04-30-2007 at 10:44 AM.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Roguefeebo View Post
    I just declared the arrays as [0] to try to designate that they were going to be handled as dynamic arrays later on. The functionality should be the same, I was just trying to make it a little more clear in the way they would be handled.
    It is NOT the same. Making it a [0] makes it a REAL array. This means you can never realloc() it. Moreover, it is zero size, meaning you can't even store a single item in it.

    Right now I'm trying to do a malloc on the struct, assign the address of that struct to a pointer and then realloc the array by the size of that pointer to assign the pointer only.
    You need to realloc() to the total size of the array plus one. Reallocing to only the size of an element never changes anything.

    Do you think it's too complicated to be helpful in learning about these kinds of things? Will I never have a need to use these things similar to the way I'm using them?
    Never, because you aren't doing it right.

  7. #7
    Registered User
    Join Date
    Apr 2007
    Posts
    5
    It is NOT the same. Making it a [0] makes it a REAL array. This means you can never realloc() it. Moreover, it is zero size, meaning you can't even store a single item in it.
    Sorry. I didn't know. I was reading one of the references online and I probably just misunderstood it. I'll change it right away, thanks,

    You need to realloc() to the total size of the array plus one. Reallocing to only the size of an element never changes anything.
    That's what I should be doing with this though:

    Code:
          addMenu = (menuStructPtr*)realloc(addMenu, ((*i+1) * sizeof(newOption)));
    Am I not using that right either?

    Never, because you aren't doing it right.
    Well I mean the concept. Not the code itself. If I were to get the code right, would I use the concept in on-the-job programming?

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Roguefeebo View Post
    Code:
          addMenu = (menuStructPtr*)realloc(addMenu, ((*i+1) *sizeof(newOption)));
    This is right, provided that *i is the last index in the array. It is clearer to just keep a variable that contains the size of the array.

    EDIT: Well, not quite. You should really stick the return value of realloc() in a different pointer variable. Imagine if realloc() fails (returns NULL). This will overwrite the addMenu pointer and you lose the entire array.

    Well I mean the concept. Not the code itself. If I were to get the code right, would I use the concept in on-the-job programming?
    A dynamically growing array? Sure, you'll use them all the time.

  9. #9
    Registered User
    Join Date
    Apr 2007
    Posts
    5
    Thanks for the help Brewbuck. I'll try to play with the code more on my own for a bit taking your input into consideration. I'll probably be back later with more questions if/when I get stuck again,

  10. #10
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    Location
    Alabama
    Posts
    1,065
    It has been said that one should allocate more memory than one needs each time and have two variables maintaining the size. Or, perhaps something like
    Code:
    #define GROW 1024
    int size = 0, len = 0;
    MYTYPE **buf = NULL, **tmp;
    while (something){
    	if (len >= size){
    		size += GROW;
    		tmp = realloc(buf, sizeof *buf * size);
    		if (tmp){
    			buf = tmp;
    		} else {
    			SNAZZY_ERROR_RECOVERY();
    		}
    	}
    	buf[len] = MYDATA(); // This creates more memory and assigns to your pointer array.
    	len++;
    }
    So that you don't have to ask for memory over and over again, but every 1024 elements or so.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamically allocated array of an abstract type
    By Zerok in forum C++ Programming
    Replies: 4
    Last Post: 11-24-2008, 06:50 AM
  2. Replies: 10
    Last Post: 05-18-2006, 11:23 PM
  3. Inserting new member into array of structs
    By cathym in forum C Programming
    Replies: 6
    Last Post: 04-17-2005, 07:10 AM
  4. Replies: 5
    Last Post: 12-05-2002, 02:27 AM
  5. Replies: 4
    Last Post: 09-12-2001, 02:05 PM