Thread: Struct *** initialization

  1. #1
    Registered User
    Join Date
    Jul 2002
    Posts
    15

    Struct *** initialization

    I am trying to allocate memory for a structure that looks like this.

    Code:
       typedef struct
       {
          int nID;
          char ** pMessage;
       } MyStruct;
    
       MyStruct ** pSections[10];
       int str[] = {0,1,10,88,1000,534,....};
    
       for (i = 0; i < 10; i++)
       {
          pSections[i] = (MyStruct **) calloc(1, sizeof(MyStruct *)*str[i]);
       }
    
       for (i = 0; i<10; i++)
       {
            for (j = 0; j<str[i]; j++)
           {
                  pSections[i][j] = ... // Some previously allocated MyStruct address allocated elsewhere using calloc(1, sizeof(MyStruct))
           }
       }
    As you can see, one dimension of the 3D array pSections, is already allocated at start up. Then the second dimension is allocated in the first for loop. As you can see the sizes of the arrays in the second dimension are not the same. I get an application crash when I assign pSections[i][j]. Not immediately though, I get the crash in calloc after I allocate say 50-60 MyStruct values (BTW, I allocate MyStruct also using calloc)

    What I am trying to do -->
    • There are N sections that are defined in a #define SECTIONS 7
    • There are X entries in each section. And each section has a differnt number of entries.
    • I allocate each array in a section using calloc.
    • I allocate each entry using calloc.
    • I Then assign each entry to the array.
    • I then try to access it with pSections[i][j]


    Any help is appreciated ...

  2. #2
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    > pSections[i] = (MyStruct **) calloc(1, sizeof(MyStruct *)*str[i]);
    I believe this should be:
    pSections[i] = calloc(1, sizeof(MyStruct)*str[i]);



    > pSections[i][j] = ... // Some previously allocated MyStruct address allocated elsewhere using calloc(1, sizeof(MyStruct))
    I assume to access, you use something like:
    pSections[i][j]->nID = ...

  3. #3
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    I am allocating space for the 2nd dimension in the array and not the structure. So I think it should be sizeof(MyStruct *) ... right? Please let me know if I assume correct.

  4. #4
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Upon further examination, it looks like your original code is ok, but you're missing an allocation step:
    Code:
       for (i = 0; i<10; i++)
       {
            for (j = 0; j<str[i]; j++)
           {
                  pSections[i][j] = malloc(sizeof(MyStruct));
                  pSections[i][j]-> = ...
           }
       }
    But you wouldn't need this if you instead had:
    MyStruct * pSections[10];

    Then you could just use:
    pSections[i][j].nID = 3; // Some previously allocated MyStruct address allocated elsewhere using calloc(1, sizeof(MyStruct))

  5. #5
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    The reason I dont use what you just described is because I already have all of these entries allocated as a result of other code. I just need to hold the pointers. So look at it this way -->

    Code:
    MyStruct ** pSections[10];
    
    is actually
    
    (MyStruct *) * pSections[10];
    So do you know why I get this unexplained crash?

  6. #6
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Did you allocate space for the data?
    pSections[i][j] = malloc(sizeof(MyStruct));

    From you original post, it sounds like yes. If so, then I'm baffled why it would crash.

  7. #7
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    pSections[i][j] = ...
    Or you may be assigning this to a previously allocated memory. That should work also.

  8. #8
    Visionary Philosopher Sayeh's Avatar
    Join Date
    Aug 2002
    Posts
    212
    You are confusing yourself with the double dereference.

    Code:
    typedef struct
       {
       int nID;
       char ** pMessage;
       }MyStruct;
    
       MyStruct **pSections[10];
       int str[] = {0,1,10,88,1000,534,....};
    
       for (i = 0; i < 10; i++)
          {
          pSections[i] = (MyStruct**) calloc(1, sizeof(MyStruct *)*str[i]);
          };
    
       for(i = 0; i<10; i++)
          {
          for (j = 0; j<str[i]; j++)
             {
             pSections[i][j] = ... // Some previously allocated MyStruct address allocated elsewhere using calloc(1, sizeof(MyStruct))
             };
          };
    Whenever you use the double-dereference ('**'), you are saying "pointer to pointer-to-block" of RAM. This is called a handle.

    Your calloc() call isn't allocating space for the block of RAM where you want to allocate data, you're actually setting the size of your initial pointer space. Then when you write your data, your scribbling into RAM.

    nasty.
    It is not the spoon that bends, it is you who bends around the spoon.

  9. #9
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    I use two callocs ... one to allocate the space for the pointers that hold the actual data and one to allocate the actual data.

    Code:
     for (i = 0; i < 10; i++)
          {
          pSections[i] = (MyStruct**) calloc(1, sizeof(MyStruct *)*str[i]);
          // ALLOCATION FOR THE POINTERS
          };
    
       for(i = 0; i<10; i++)
          {
          for (j = 0; j<str[i]; j++)
             {
             pSections[i][j] = ... // Some previously allocated MyStruct address allocated elsewhere using calloc(1, sizeof(MyStruct))
             // NOTE THAT I ALLOCATE SOMEWHERE ELSE THIS MEMORY
             };
          };
    Is this correct?

  10. #10
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    I think this is what you're trying to do. In my sample code I've only used one "real data" struct, but I suppose you'll have lots of them. There's a simple diagram to show what's going on as well. It starts with an array of pointers. Each element receives a pointer to a malloc'd area of memory for holding a number of more pointers. These pointers are then given the address of the real data structures.
    Code:
    /*
    [Array Pointer 0]---->[Data Pointer 0]--->[Real Data Item]
                          [Data Pointer 1]--->[Real Data Item]
                          [Data Pointer 2]--->[Real Data Item]
                          [Data Pointer 3]--->[Real Data Item]
                          [Data Pointer 4]--->[Real Data Item]
                          [Data Pointer 5]--->[Real Data Item]
    
    [Array Pointer 1]---->[Data Pointer 0]--->[Real Data Item]
                          [Data Pointer 1]--->[Real Data Item]
    
    [Array Pointer 3]---->[Data Pointer 0]--->[Real Data Item]
                          [Data Pointer 1]--->[Real Data Item]
                          [Data Pointer 2]--->[Real Data Item]
                          [Data Pointer 3]--->[Real Data Item]
                          [Data Pointer 4]--->[Real Data Item]
    ....                      
    [Array Pointer 9]---->[Data Pointer 0]--->[Real Data Item]
                          [Data Pointer 1]--->[Real Data Item]
                          [Data Pointer 2]--->[Real Data Item]
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct Data
    {
      int i;
    };
    
    struct Data RealData = {1};
    
    int main(void)
    {
      struct Data **pSections[10];
      /* Now size for 10 sections */
      int SectionsCount[] = {5, 2, 3, 5, 6, 1, 3, 2, 5, 9}; 
      int i, j;
      
      for (i = 0; i < 10; ++i)
      {
        /* Malloc space for SectionsCount[i] number of pointers */
        pSections[i] = malloc(sizeof(pSections[i])*SectionsCount[i]);
        for (j = 0; j < SectionsCount[i]; ++j)
        {
          pSections[i][j] = &RealData;
        }
      }
      
      for (i = 0; i < 10; ++i)
      {
        for (j = 0; j < SectionsCount[i]; ++j)
        {
          printf ("Main Array item %d, Sub element %d, Value: %d\n", i, j, pSections[i][j]->i);
        }
      }
      
      return 0;
    }
    
    /*
    Output
    
    Main Array item 0, Sub element 0, Value: 1
    Main Array item 0, Sub element 1, Value: 1
    Main Array item 0, Sub element 2, Value: 1
    Main Array item 0, Sub element 3, Value: 1
    Main Array item 0, Sub element 4, Value: 1
    Main Array item 1, Sub element 0, Value: 1
    Main Array item 1, Sub element 1, Value: 1
    Main Array item 2, Sub element 0, Value: 1
    Main Array item 2, Sub element 1, Value: 1
    Main Array item 2, Sub element 2, Value: 1
    Main Array item 3, Sub element 0, Value: 1
    Main Array item 3, Sub element 1, Value: 1
    Main Array item 3, Sub element 2, Value: 1
    Main Array item 3, Sub element 3, Value: 1
    Main Array item 3, Sub element 4, Value: 1
    Main Array item 4, Sub element 0, Value: 1
    Main Array item 4, Sub element 1, Value: 1
    Main Array item 4, Sub element 2, Value: 1
    Main Array item 4, Sub element 3, Value: 1
    Main Array item 4, Sub element 4, Value: 1
    Main Array item 4, Sub element 5, Value: 1
    Main Array item 5, Sub element 0, Value: 1
    Main Array item 6, Sub element 0, Value: 1
    Main Array item 6, Sub element 1, Value: 1
    Main Array item 6, Sub element 2, Value: 1
    Main Array item 7, Sub element 0, Value: 1
    Main Array item 7, Sub element 1, Value: 1
    Main Array item 8, Sub element 0, Value: 1
    Main Array item 8, Sub element 1, Value: 1
    Main Array item 8, Sub element 2, Value: 1
    Main Array item 8, Sub element 3, Value: 1
    Main Array item 8, Sub element 4, Value: 1
    Main Array item 9, Sub element 0, Value: 1
    Main Array item 9, Sub element 1, Value: 1
    Main Array item 9, Sub element 2, Value: 1
    Main Array item 9, Sub element 3, Value: 1
    Main Array item 9, Sub element 4, Value: 1
    Main Array item 9, Sub element 5, Value: 1
    Main Array item 9, Sub element 6, Value: 1
    Main Array item 9, Sub element 7, Value: 1
    Main Array item 9, Sub element 8, Value: 1
    
    */
    [edit]
    Also note, my code doesn't show free() and error checking on malloc, which you should be doing
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  11. #11
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    Hello hammer,
    Thank you for your reply. You seem to have used malloc and I have used calloc ... Other than that I use the same sematics you use ... the only differences I see are -->

    Code:
        you use --> malloc (sizeof(pSections[i])*SectionCounts[i])
        I use --> calloc (1, sizeof(MyStruct **) * str[i]);
    
        Note that I used sizeof(MyStruct**) instead of sizeof(pSections[i]).
        Also note that reversed the parameters to calloc, I say 1 element with sizeof(MyStruct**)*str[i] instead of calloc(str[i], sizeof(MyStruct**)) ... Will this interpret differently?
    I had another concern --> how will the compiler/runtime environment interpret pSections[i][j] ... I mean will it automatically know where to go when I refer to it this way or does it perform the calculation of pSections + (i*j*sizeof(Data*)) to find out the index of what I am looking for. I read somewhere that when I declare an array str[10][20], it allocates it as a single byte array and then for all arithmetic on this array, it calculates position as follows -->
    str[1][2] means str + 1*2 ...

    If that is the case then my program will obviously fail because each element in the second dimension is of different sizes. Please advise.

  12. #12
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >> You seem to have used malloc and I have used calloc
    Your use of calloc is wrong for two reasons.

    1) The first thing you do with the newly allocated memory is put data into in. Therefore, ensuring it's zero (through use of calloc()) is pointless, as you never use the zero value.

    2)calloc() sets all memory bits to zero, but this does not guarantee a NULL pointer. There's an entry in the eskimo FAQ about this.

    In short, use malloc.

    >>sizeof(MyStruct**) instead of sizeof(pSections[i])
    Those two are the same in this case, but style rules would recommend that you use whatever you're assigning to in the determination of the size of memory. Looking back at my code, it should have actually been sizeof(*pSections[i]), but this still equates to the size of a pointer, so there's no actual difference.

    >>how will the compiler/runtime environment interpret pSections[i][j]
    Correctly. pSections is an array, so pSections[i] will take you to a specific element of the array. Dereferencing that takes you to the dynamically created array, which is variable size, and can be indexed through [j]. Using the arrow notation on that address will derefence it again to take you to the real data structure. Hopefully this is what my code showed you.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  13. #13
    Registered User
    Join Date
    Oct 2003
    Posts
    2
    I think your usage of calloc may be causing the problem. How about trying:

    Code:
    for (i = 0; i < 10; i++)
    {
        pSections[i] = calloc(str[i], sizeof(MyStruct *));
    }

  14. #14
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>I think your usage of calloc may be causing the problem.
    Did you miss what I said in my previous post?

    http://www.eskimo.com/~scs/C-faq/q7.31.html
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  15. #15
    Registered User
    Join Date
    Oct 2003
    Posts
    2
    Ah, you're right, I'm sorry.

    Just so I understand you, you're saying that if you want an array of NULL pointers, you might as well just malloc it yourself and then have a loop to fill with NULLs?

    Also, is there any difference between:
    Code:
    int *p;
    p = calloc(1, 10 * sizeof(int));
    
    and
    
    int *p;
    p = calloc(10, sizeof(int));

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. memory issue
    By t014y in forum C Programming
    Replies: 2
    Last Post: 02-21-2009, 12:37 AM
  2. Link List math
    By t014y in forum C Programming
    Replies: 17
    Last Post: 02-20-2009, 06:55 PM
  3. Struct Initialization
    By carrotcake1029 in forum C Programming
    Replies: 5
    Last Post: 05-06-2008, 02:27 PM
  4. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  5. Search Engine - Binary Search Tree
    By Gecko2099 in forum C Programming
    Replies: 9
    Last Post: 04-17-2005, 02:56 PM