Search code examples
clinked-listsavefile-read

Loading binary file to unknown struct type


I have a problem reading from binary file and casting it to a unknown type of struct...

  • Should I really avoid having the save/load functions inside my Linked List code?
  • Is it because the GCC compiler I'm using stacks the struct with more data to conveniently store in memory, and since when loading the function doesn't know about this "offsets"?

I'm writing a generic linked list in C, and it is intended to be a header file, so I can just use it anywhere. Since it's going to be a generic type list, the header will not know about the type of data on the list (I'm looking at mixed types, so structs). For saving data, I just pass the address of the data, and the length of it, extracted from sizeof(struct). The reading is the same concept, using fread(container, sizeof(struct), 1, FILE), which is passed by the calling program, again extracting se size using sizeof(struct). But in practice, it does not work...

#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
#include <string.h>

typedef struct tagNode{
    void            *data;
    struct tagNode  *next_Node;
} Node;

typedef struct tagLinkedList{
    Node *Head;
    int   Size;
} LinkedList;

int LinkedList_New(LinkedList *llist){
    llist->Head = NULL;
    llist->Size = 0;
    return 1;
}

int LinkedList_Insert(LinkedList *llist, int index, void *Data, size_t s_Data){
    int cur_index = 0;
    if(index > llist->Size || index < 0)
        index = 0;

    Node *newNode = malloc(sizeof(Node));
    newNode->data = malloc(s_Data);
    if(newNode       == NULL){return 0;}
    if(newNode->data == NULL){return 0;}
    newNode->data = Data;

    Node *currentNode = llist->Head;
    Node *lastNode    = llist->Head;

    if(index == 0){
        newNode->next_Node = llist->Head;
        llist->Head = newNode;
    }else{
        while(llist->Head->next_Node != NULL && cur_index != index){
            if(cur_index == index){
                newNode->next_Node  = currentNode;
                lastNode->next_Node = newNode;
            }else{
                lastNode    = currentNode;
                currentNode = currentNode->next_Node;
                cur_index++;
            }
        }
    }
    llist->Size += 1;
}

int LinkedList_Save(char *Path, LinkedList *llist, size_t sData){
    FILE *fp;
    fp = fopen(Path, "w");
    if(fp == NULL){return -1;}

    Node *currentNode;
    currentNode = llist->Head;

    while(currentNode != NULL){
        fwrite(currentNode->data, sData, 1, fp);
        currentNode = currentNode->next_Node;
    }
    fclose(fp);
    return 1;
}

int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
    FILE *fp;
    fp = fopen(Path, "r");
    if(fp == NULL){fclose(fp);return -1;}

    while(!feof(fp)){
        void *Data = malloc(sData);
        if(Data == NULL){fclose(fp);return -1;}
        fread(Data, sData, 1, fp);
        LinkedList_Insert(llist, 0, Data, sData);
    }
    fclose(fp);
    return 1;
}
#endif // LINKEDLIST_H_INCLUDED

And my currently testing subject:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LinkedList.h"
typedef struct{
    int a;
    char b[5];
} tempo;

int main(){
    tempo teste = {5, "oito"};

    LinkedList lista;
    LinkedList_New(&lista);
    LinkedList_Insert(&lista, 0, &teste, sizeof(tempo));
    LinkedList_Save("data.txt", &lista, sizeof(tempo));
    printf("%s", ((tempo*)lista.Head->data)->b);
    LinkedList ls2;
    LinkedList_New(&ls2);
    LinkedList_Load("data.txt", &ls2, sizeof(tempo));

    printf("%s", ((tempo*)ls2.Head->data)->b);

    return 1;
}

The first printf shows me the b variable in the struct, which means the list is working like its supposed to.

But the second printf, if used to show the a variable(int), I get a random number(something like 8712382), and if used to show the b variable, I get just "L"


Solution

  • you have a problem in your LinkedList_load function. update it to the following

    int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
            FILE *fp;
            fp = fopen(Path, "rb");
            if(fp == NULL){fclose(fp);return -1;}
            fseek(fp,0L,SEEK_SET);
            while(!feof(fp)){
                    void *Data = malloc(sData);
                    if(Data == NULL){fclose(fp);return -1;}
                    int readed=fread(Data, sData, 1, fp);
                    if(readed==0){return -1;}
                    /*you were displaying the last reading that contains 
                    *nothing, the previous check solves the problem.
                    */
                    printf("readed %d items:  \n",readed);
                    LinkedList_Insert(llist, 0, Data, sData);       
            }
           fclose(fp);
    

    }