Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

C Programming (Dynamic memory (re)allocation)

Options
  • 21-10-2011 2:41pm
    #1
    Registered Users Posts: 498 ✭✭


    I have a structure E.g.
    typedef struct{
    char charArray[10];
    int someInteger;
    }[B]myStruct[/B];
    
    Then inside main() I do this
    void main(void)
    {
    myStruct a[1];
    myStruct *sPtr = a;
    
    func(&sPtr);
    ...
    // code that continues to work with the struct array (a)
    }
    
    The above passes a pointer to the pointer that points to the start of my structure array. The reason I'm not passing the pointer by value is because I may have to change the value of the pointer within func, and will need this change available after func returns back in main.
    void func(myStruct **ptr)
    {
    // this function reads in from a binary file using fread. Each read reads in sizeof(myStruct) bytes from the file.
    // Everytime I successfully read in that many bytes from the file, I then want to re-allocate the amount of memory available for my structure array (a) in main().
    // So on the first successful read, I'll first malloc enough space to store the first record, and on subsequent calls I'll realloc enough space to store existing records plus one more.
    
    // Here's my attempt at a re-alloc
    ptr = (myStruct **) realloc (*ptr, (loopCounter+1) * sizeof(myStruct));
    
    // realloc above does not return NULL (i.e. failure),
    but when I try to store something in:
    *ptr[loopCounter+1] = structure that holds contents of read
    I get a memory error
    }
    
    Truth is *ptr[0] on the first iteration before the realloc, holds stuff fine and I can access it, change it, etc. But after I realloc memory available to the array, I still can't write to array indexes greater than zero.

    What am I doing wrong?


Comments

  • Registered Users Posts: 2,023 ✭✭✭Colonel Panic


    You're trying to reallocate memory that wasn't allocated with malloc which is "undefined behaviour".

    When you declare
    myStruct a[1];
    

    Where do you think that is allocated?


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    You're trying to reallocate memory that wasn't allocated with malloc which is "undefined behaviour".

    When you declare
    myStruct a[1];
    

    Where do you think that is allocated?
    this.

    Op, the one you passed to the function was allocated on the stack while mallocs are allocated on the heap.


  • Registered Users Posts: 498 ✭✭bobbytables


    You're trying to reallocate memory that wasn't allocated with malloc which is "undefined behaviour".

    When you declare
    myStruct a[1];
    
    Where do you think that is allocated?

    I assumed that memory allocated with malloc or by simply declaring memory to be allocated resulted in the same thing. I guess that is my downfall.

    So how do I declare an array of unknown size, which I can get a pointer to, which I can then dynamically scale the memory allocated to it, which is then referred to by the same pointer.


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    I assumed that memory allocated with malloc or by simply declaring memory to be allocated resulted in the same thing. I guess that is my downfall.

    So how do I declare an array of unknown size, which I can get a pointer to, which I can then dynamically scale the memory allocated to it, which is then referred to by the same pointer.
    Yep that was an incorrect assumption.
    myStruct *a = (myStruct*) malloc(sizeof(myStruct));
    if (a == NULL)
     return;
    myStruct *sPtr = a;
    func(&sPtr);
    
    

    By the way you don't need the extra pointer at all..just pass &a instead. Also if you really want to be strict, you should have int as the return type for your main function if it's proper C.


  • Registered Users Posts: 2,023 ✭✭✭Colonel Panic


    Also make sure you free anything you allocate on the heap!


  • Advertisement
  • Registered Users Posts: 498 ✭✭bobbytables


    OK as you suggested, lets get rid of the second pointer, and instead of declaring an array in main(), we just declare a single pointer to a structure of the type myStruct and instead pass &a to func.

    That's fine. But how would I go about scaling up the size of a in func us realloc?

    Lets say my prototype for func is now
    void func(myStruct *ptr)
    
    My realloc line is
    ptr = (myStruct *) realloc (ptr, (records+1) * sizeof(myStruct));
    
    Which fails on the second iteration, where (records+1) > 1

    Alternatively, if my function prototype is **ptr, then realloc works (changing references to *ptr), but the line where I would then assign the new values available on the iteration

    *ptr[records] = some new instance of myStruct

    This fails,


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    You will need to pass a pointer to a pointer like you did already.
    void func(myStruct **ptr);
    

    in main call it as
    func(&a);
    

    Then in the function you will have to pass the value of the pointer which is the pointe to the memory into the realloc func and assign the value back so you'll have:
    *ptr = (myStruct *) realloc (*ptr, (records+1) * sizeof(myStruct));
    

    And don't forget to free the memory as it's only good practice as it could lead to memory leaks in a larger program.

    Edit: Sorry I only half read your post. Can you explain more into what's happening the 2nd part of your post.


  • Registered Users Posts: 498 ✭✭bobbytables


    Ok that's fine, and that does work, however on the first loop iteration, I am just assigning the structure I've read in from the binary file to the array like this
    *ptr[records] = just_read_in_record;
    
    That works, and I can verify contents through debugger. Just before I do that assignment I check the following
    printf("sizeof(ptr): %d, sizeof(*ptr): %d, sizeof(**ptr): %d\n", sizeof(ptr), sizeof(*ptr), sizeof(**ptr));
    
    and their sizes are 4, 4, 20 respectively, which is correct, as the first two are pointers and the last one is == sizeof(myStruct).

    Now on the second loop iteration, after I've read in the next record from the file, I now make your call to realloc, and that works fine. However again just before I make my assignment of the second read in value to *ptr[records], where records would now be 1 (meaning the second index in the array), I again print out the various variable sizes, and they are still 4, 4, 20. Immediately after that I get a memory access violation.

    I am assuming I am getting this error because the value of sizeof(**ptr) should have been 40 (instead of 20), since I did a realloc prior to that, increasing the memory needed to 2 x sizeof(myStruct).

    Any ideas why I'm getting the access violation error?


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    I am guessing here but should it not be
    *ptr = (myStruct *) realloc (*ptr, (records+1[b]+1[/b]) * sizeof(myStruct));
    

    Since records is 0 based?


  • Registered Users Posts: 498 ✭✭bobbytables


    Yeah I thought that before also, but on the first iteration, I'm not realloc(ing) at all. Only when my (int)records are > 0, then I do the realloc, so the first time that would get called, it would be (1+1) * sizeof(myStruct), and this would be done prior to my trying to assign any thing to *ptr[1].

    Got any other suggestions?


  • Advertisement
  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    Is there any chance we can see your code as it's used. It's hard to know what is happening from these snippets.

    At least the loop structure and how you increment reports var etc.


  • Registered Users Posts: 498 ✭✭bobbytables


    tmp is a instance of myStruct, which just temporarily holds the data read in from the file until we store it in the current array element.

    records = 0; before loop starts.
    while((rec_read = fread(&tmp, sizeof(myStruct), 1, cfPtr)) == 1) // while we're still able to read a record...
        {    
            printf("%s\t%d\t%f\n", tmp.Name, tmp.Num, tmp.Date);
    
            if(records) // i.e. beyond the first record
            {    
                printf("scaling up to contain %d\n", records+1);
                *ptr = (myStruct *) realloc (*ptr, (records+1) * sizeof(myStruct)));
            }
    
            printf("sizeof(ptr): %d, sizeof(*ptr): %d, sizeof(**ptr): %d\n", sizeof(bches), sizeof(*bches), sizeof(**bches));
    
            *ptr[records] = tmp;
            
            printf("Just stored in array[%d]: %s:%d:%.2f\n", records, ptr[records]->Name, ptr[records]->Num, ptr[records]->Date);
    
            records++;
        }
    

    So in the above, the line
    *ptr[records] = tmp;
    
    causes the access violation error on the second iteration.


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    (*ptr)[records] = tmp;
    

    Edit: Just this one. I think without the () you will have precedence problems.

    Yep the [] operators has precedence over the dereference operator *
    http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence


  • Registered Users Posts: 498 ✭✭bobbytables


    Fair play, that's what I was missing ;)

    Works!


Advertisement