简体   繁体   中英

Saving (and reading) Linked List (that containts dynamic strings) Into Binary File In C

I'm trying to read/write linked list into a binary file, the problem is that this list contains dynamically allocated strings and when I try to read from the file the linked list, I get in the string field, address instead of the string value . Someone knows maybe what is the problem?


    void saveProject(FrameNode* headFrame, char* filePath)
    {
    FILE* projectFile = fopen(filePath, WRITING_MODE);
    FrameNode* currentFrame = headFrame;
    if (projectFile) // making sure the fopen() didn't failed
    {
        while (currentFrame != NULL) // making sure the list isn't empty
        {
            fseek(projectFile, 0, SEEK_END); // writing the node to the end of the file
            // writing the currentNode into the file and returning the value of ->"next"
            fwrite(currentFrame->frame, sizeof(Frame), 1, projectFile);
            currentFrame = currentFrame->next; // moving to the next frame
        }
        fseek(projectFile, 0, SEEK_SET); // returning the seek of the file to the start
        fclose(projectFile);
    }
}


void openProject(FrameNode** headFrame, char* filePath)
{
    FILE* projectFile = fopen(filePath, READING_MODE);
    FrameNode* currentFrame = *headFrame;
    int numOfFrames = 0;
    int i = 0;

    if (projectFile) // making sure the fopen() function didn't failed
    {
        // making sure the headFrame doesn't point to existing list
        dealloc_linked_list(*headFrame);
        *headFrame = NULL;

        // finding the number of nodes (=frames) in the projectFile file
        fseek(projectFile, 0, SEEK_END);
        numOfFrames = (int)(ftell(projectFile) / sizeof(Frame));
        fseek(projectFile, 0, SEEK_SET);

        for (i = 0; i < numOfFrames; i++)
        {
            // reading the next frame in the list
            fseek(projectFile, sizeof(Frame) * i, SEEK_SET);
            addFrameFromFile(headFrame, projectFile);
        }

    }
    fclose(projectFile);
}

void addFrameFromFile(FrameNode** headFrame, FILE* projectFile)
{
    FrameNode* newFrame = NULL;

    if (*headFrame == NULL) // in case the list is empty
    {
        *headFrame = (FrameNode*)malloc(sizeof(FrameNode));
        newFrame = *headFrame;
    }
    else // if the list isn't empty, the function will search for the last node in the list
    {
        newFrame = findLastFrame(*headFrame);
        newFrame->next = (FrameNode*)malloc(sizeof(FrameNode));
        newFrame = newFrame->next;
    }
    
    // adding the data from the file to the newFrame
    newFrame->frame = (Frame*)malloc(sizeof(Frame));
    fread(newFrame->frame, sizeof(Frame), 1, projectFile);

    newFrame->next = NULL; // making the frame be the last in the list
}

And This is the linked list node structs:

// the content
typedef struct Frame
{
    char* name;
    unsigned int    duration;
    char* path;
} Frame;


// Link (node) struct
typedef struct FrameNode
{
    Frame* frame;
    struct FrameNode* next;
} FrameNode;

When I try to read the file, I get the next output: click me to see the screenshot of the output The first printing is the original list that I wrote into the file, and the second is the list I created from the file using the openProject() function.

Thanks in advance

The fwrite() function is used to write the binary values from the active RAM in your program to a file, so when you call fwrite(currentFrame->frame,sizeof(Frame),1,projectFile) you're asking the system to copy sizeof(Frame) (times one) bytes from the memory pointed to by currentFrame->frame into your file.

In your setup, a Frame has two char* in it, but fwrite does not care about this. The fwrite() function will just treat these pointers like any other binary value, and copy the memory addresses, which will soon be incorrect, into the file.

If you want to save the important parts of your linked list into a file so you can reproduce a linked list with the same data in the future you need to actually copy the contents of the strings into the file, like so:

void saveProject(FrameNode* headFrame, char* filePath)
{
    FILE* projectFile = fopen(filePath, WRITING_MODE);
    FrameNode* currentFrame = headFrame;
    if (projectFile == NULL) // making sure the fopen() didn't failed
        return;
    while (currentFrame != NULL) // making sure the list isn't empty
    {
            fprintf(projectFile,"%s%d%s",currentFrame->frame->name,currentFrame->frame->duration,currentFrame->frame->path);
            currentFrame = currentFrame->next; // moving to the next frame
    }
    fclose(projectFile);
}

fprintf() works just like printf , except it writes to a file instead of stdout , so it will write the strings into the file not the pointers that point to them.

Note that all the fseek s in your code are unnecessary as the file cursor is automatically moved as you write to the file.

To produce the new linked list again from the file you can use fscanf() in a loop, but make sure you allocate memory for your strings when you copy them from the file.

Regarding;

typedef struct Frame
{
    char* name;
    unsigned int    duration;
    char* path;
} Frame;

and

 fwrite(currentFrame->frame, sizeof(Frame), 1, projectFile);

the call to fwrite() is outputting the contents of an instance of Frame However, that does NOT output the data to be found where the pointers point.

Also, after writing out those pointers, then trying read them back in, the pointers are now meaningless.

Suggest modify the typedef... Frame to actually contain the data rather than pointers to the data.

Suggest:

typedef struct Frame
{
    char name[ MAX_NAME_LEN ];
    unsigned int    duration;
    char path[ MAX_PATH_LEN ];
} Frame;   

The will also eliminate the calls to malloc() and family, except for obtaining an instance of Frame

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM