0

I have an assignment C program where I have an array of automobiles (a struct). I made this array the way we've been taught disjoint DM in class. I don't know how I would save and retrieve it with a bin file.

Fist, I made a double pointer and allotted the needed space for 100 autos:

AUTO** autoInventory;
int size = 100;
int eSize = 0;

autoInventory = calloc(sizeof(AUTO*), size);

Next, each time the user adds an auto (the # autos actually in the array is tracked by a variable called eSize), a new 'node' is made:

autoInventory[*eSize] = makeNode();

AUTO* makeNode()
{
    AUTO* result = calloc(sizeof(AUTO), 1);

    //make sure it works

    return result;


}

I can see that the autos are being successfully saved because I have a function that prints all the indexes and info out, and this is as far as we covered the topic in class. Here are my save and load functions, but they apparantly do not work as the program crashes. I've tried several approaches to save it to a bin file but all of them throw errors, mostly about writing to a place where it's not allowed. Any suggestions?

I know that to save an array on the stack you just call something like this:

fwrite(myArray, sizeof(int), eSize, ptr);//given another fwrite function saved eSize before this one

But how about for the array I'm dealing with?

  • You have an array of pointers. Presumably, what you want to write to the file and later read back is not the pointers themselves (which the `fwrite()` call you present seems to be trying to do), but rather the data to which they point. – John Bollinger Nov 11 '22 at 15:36
  • 1
    Frankly, my first inclination would be to *not* use an array of pointers in the first place, but rather an array of actual `AUTO`. However, that does not seem like it would be well described by the term "disjoint dynamic memory allocation" (though that specific term is unfamiliar to me). And it would require significant changes elsewhere in your program. – John Bollinger Nov 11 '22 at 15:39
  • 1
    You have bug. Signature of `calloc` is `void *calloc(size_t nitems, size_t size)` where `nitems` - is number of elements and `size` - is size of each element. But in your code you confused the arguments – cooleck Nov 11 '22 at 15:40
  • 1
    It's hard to call that a *bona fide* bug, @cooleck. It's potentially a bit confusing to humans, perhaps enough so to foster genuine bugs elsewhere, but the memory allocated by `calloc()` is all in a single block, and its size is insensitive to the order of the arguments. – John Bollinger Nov 11 '22 at 15:43

1 Answers1

0

Since the code you presented is not complete, I made a new, simple program. It's a little bit different from the code you provided, particularly in naming. But I hope it could help you anyway.

I should mention that I am not sure what you mean by "disjoint dynamic memory allocation". Also, I am not sure about the term "BIN file", whether it means a "binary file", the .bin file name extension or some other thing. You may want to adjust my solution to your needs in this regard. Or, if you wish, provide more detail in the comments, and I'll try to adjust my solution accordingly.

As you see, when it comes to memory management, I'm not freeing memory in the code. Instead, I put only comments in the places where you might need to do it. This is only because I think additional code would clutter the existing code too much to be understandable. In a usual project, you may want to set another rules when it comes to freeing memory. Particularly, you may read:

#include <stdlib.h>
#include <stdio.h>

struct auto_t {
    int data;
};

struct auto_t * make_node (void) {
    return calloc(1, sizeof (struct auto_t));
}

int main (int argc, char * argv[]) {
    if (argc != 2) {
        // If there are no or more than 1 arguments to the program
        return EXIT_FAILURE;
    }

    // ALLOCATING MEMORY AND INITIALIZING

    int auto_inventory_size = 100;

    struct auto_t ** auto_inventory = calloc(auto_inventory_size, sizeof (struct auto_t *));
    if (auto_inventory == NULL) {
        // If calloc failed
        return EXIT_FAILURE;
    }

    struct auto_t ** auto_inventory_read = calloc(auto_inventory_size, sizeof (struct auto_t *));
    if (auto_inventory_read == NULL) {
        // If calloc failed
        // Here you may want to free memory
        return EXIT_FAILURE;
    }

    for (int k = 0; k < auto_inventory_size; ++k) {
        auto_inventory[k] = make_node();
        if (auto_inventory[k] == NULL) {
            // If calloc in make_node failed
            // Here you may want to free memory (both the
            //  whole memory for auto_inventory, and the
            //  memory for auto_inventory_read allocated
            //  so far
            return EXIT_FAILURE;
        }
        auto_inventory[k]->data = k;

        auto_inventory_read[k] = make_node();
        if (auto_inventory_read[k] == NULL) {
            // If calloc in make_node failed
            // Here you may want to free memory (both the
            //  whole memory for auto_inventory, and the
            //  memory for auto_inventory_read allocated
            //  so far
            return EXIT_FAILURE;
        }
    }

    // WRITING TO A FILE

    // Open
    // Note the mode string is "a". If you need, you can
    //  use the "ab", "w" or "wb" mode strings (see man 3
    //  fopen). Because of "a", you need to remove the
    //  created file if you would like to run the program
    //  the second time or more, otherwise results will be
    //  not as expected
    FILE * f = fopen(argv[1], "a");
    if (f == NULL) {
        // If fopen failed
        // Here you may want to free memory
        return EXIT_FAILURE;
    }

    // Write
    for (int k = 0; k < auto_inventory_size; ++k) {
        // Depending on your needs, you may want to check
        //  the return value of fwrite. Here I decided
        //  to omit it
        fwrite(auto_inventory[k], sizeof (struct auto_t), 1, f);
    }

    // Close
    if (fclose(f) != 0) {
        // If fclose failed
        // Here you may want to free memory
        return EXIT_FAILURE;
    }

    // READING FROM A FILE

    // Open
    // Note the mode string is "r". If you need, you can
    //  use the "rb" mode string (see man 3 fopen)
    f = fopen(argv[1], "r");
    if (f == NULL) {
        // If fopen failed
        // Here you may want to free memory
        return EXIT_FAILURE;
    }

    // Read
    for (int k = 0; k < auto_inventory_size; ++k) {
        // Depending on your needs, you may want to check
        //  the return value of fread. Here I decided
        //  to omit it
        fread(auto_inventory_read[k], sizeof (struct auto_t), 1, f);
    }

    // Close
    if (fclose(f) != 0) {
        // If fclose failed
        // Here you may want to free memory
        return EXIT_FAILURE;
    }

    // Verify that reading from file went OK
    for (int k = 0; k < auto_inventory_size; ++k) {
        printf("[DEBUG] auto_inventory[k]->data == %d\n", auto_inventory[k]->data);
        printf("[DEBUG] auto_inventory_read[k]->data == %d\n", auto_inventory_read[k]->data);
        printf("\n");
    }

    // Here you may want to free memory

    return EXIT_SUCCESS;
}
user20276305
  • 95
  • 1
  • 7