简体   繁体   中英

Reading struct from binary file (C)

I need your help with reading struct from binary file, the "Grocery read_from_file ()..." function Can't get this to work!

Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ctype.h>
#include <conio.h>

struct grocerylist
{
    int iD;
    char grocery[30];
    float amount;
    char unit[10];
};



Grocery set_size_of(Grocery* list, int index);

Grocery input(int index);

void print_grocerylist(Grocery* list, int* index);

void write_to_file(FILE* file_pointer, Grocery* list, int index);

Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index);

void change_item(Grocery* list, int index);

void remove_item(Grocery* list, int* index);

int main()
{

    Grocery* list = (Grocery*)malloc(sizeof(Grocery)*1);            //Grocery-array allocated memory for 1 struct
    int index = 0, choice = 0;
    FILE* file_pointer = NULL;

    printf("Hey there user!\n");

    while(choice != 7){
        system("cls");
        printf("Menu\n");
        printf("1 - Add an item to the list.\n2 - Print the contents of your current list.\n3 - Print the contents to file.\n4 - Read from file.\n5 - Change an item on the list.\n6 - Remove item from the list.\n7 - close the program.\nChoose: ");
        scanf("%d", &choice);
        printf("\n");

        switch(choice){
            case 1:
                list[index] = input(index);
                index++;
                *list = set_size_of(list, index);                           //Reallocating memory for the array of grocery-structs.
                fflush(stdin);
                break;                                              //Add item
            case 2:
                print_grocerylist(list, &index);                    //Print list
                fflush(stdin);
                break;
            case 3:
                write_to_file(file_pointer, list, index);           //print to file
                fflush(stdin);
                break;
            case 4:
                *list = read_from_file(file_pointer, list, &index);         //read from file
                fflush(stdin);
                break;
            case 5:
                change_item(list, index);                           //change item
                fflush(stdin);
                break;
            case 6:
                remove_item(list, &index);                          //remove item
                index--;
                fflush(stdin);
                break;
            case 7:
                free(list);
                exit(EXIT_SUCCESS);                                 //End program
                break;
            default:
                printf("Wrong input, please try again!");
                fflush(stdin);
                getch();
                break;
        }
    }
    return 0;
}

Grocery set_size_of(Grocery* list, int index){             //reallocates memory.

    list = realloc(list, (index+1)*sizeof(Grocery));

    return *list;
}

Grocery input(index){

    Grocery tmp;
    int x = 0;

    tmp.iD = index +1;

    fflush(stdin);
    printf("Grocery: ");
    gets(tmp.grocery);

    while(x == 0){
        fflush(stdin);
        printf("Amount: ");
        x = scanf("%f", &tmp.amount);
        if(x == 0){
            puts("Error, please try again!");
        }
    }

    fflush(stdin);
    x = 0;
    while(x == 0){
        printf("Unit: ");
        gets(tmp.unit);
            if(isalpha(*tmp.unit)){
                x = 1;
            }else{
                x = 0;
                puts("Error: please try again!\n");
            }
    }
    printf("\n");

    return tmp;
}

void print_grocerylist(Grocery* list, int* index){

    int i;

    system("cls");
    printf("The grocery list contains:\n");
    printf("Item            Amount      Unit");
        for(i=0;i<*index;i++)
        {
            printf("\n%d: %-10s    %5.1f    %6s", list[i].iD, list[i].grocery, list[i].amount, list[i].unit);
        }
        printf("\n");
    getch();
    printf("Press any key to continue.\n");
}

void write_to_file(FILE* file_pointer, Grocery* list, int index){               //works just fine afaik.. Prints the index at the start, fills it up with all the rest.

    char filename[30];
    memset(filename, '\0', sizeof(filename));

    printf("What is the name of the file you wish to write to?: ");
    scanf("%s", filename);
    strcat(filename, ".txt");

    file_pointer = fopen(filename, "wb");
    if(file_pointer == NULL){
        printf("Error!");
        return;
    }else{
        fflush(stdin);
        printf("File opened successfully!\n");
        fwrite(&index, sizeof(int), 1, file_pointer);
        fwrite(list, sizeof(Grocery), index, file_pointer);
        printf("File written.");
        getch();
    }

    fclose(file_pointer);

    return;
}

Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index){     //Can't get this to work...

    char filename[30];
    memset(filename, '\0', sizeof(filename));

    printf("What is the name of the file you wish to read from?: ");
    scanf("%s", filename);
    strcat(filename, ".txt");

    file_pointer = fopen(filename, "rb");
    if(file_pointer == NULL){
        printf("Error!");
        return *list;
    }else{
        fflush(stdin);
        free(list);
        printf("File opened successfully!\n");
        fread(index, sizeof(int), 1, file_pointer);
        printf("Index %d read.\n", *index);
        list = (Grocery*)calloc(*index, sizeof(Grocery));
        fread(list, sizeof(Grocery), (*index), file_pointer);
        printf("File read.");
        getch();
        fflush(stdin);
    }

    fclose(file_pointer);

    return *list;
}

void change_item(Grocery* list, int index){     //Basically it's a more complex version of "Grocery input()" were we look to the ID/index and alter the information.

    int x = 0, id, item, choice;

    print_grocerylist(list, &index);

    printf("Which item would you like to change?\nID number: ");
    scanf("%d", &id);
    printf("\nWhat do you want to change?\n1 - Grocery.\n2 - Amount.\n3 - Unit.\nChoose: ");
    scanf("%d", &choice);

    switch(choice){
        case 1:
            fflush(stdin);
            printf("Grocery: ");
            for(item = 0; item <= index; item++){
                if(list[item].iD == id){
                    gets(list[item].grocery);
                }
            }
            break;
        case 2:
            while(x == 0){
                fflush(stdin);
                printf("Amount: ");
                for(item = 0; item <= index; item++){
                    if(list[item].iD == id){
                        x = scanf("%f", &list[item].amount);
                    }
                }
                if(x == 0){
                    puts("Error, please try again!");
                }
            }
            break;
        case 3:
            fflush(stdin);
            x = 0;
            printf("Unit: ");
            for(item = 0; item <= index; item++){
                if(list[item].iD == id){
                    gets(list[item].unit);
                        if(isalpha(*list[item-1].unit)){
                            x = 1;
                        }else{
                            x = 0;
                            puts("Error: please try again!\n");
                        }
                }
            }
            break;
        default:
            printf("\nError! Please try again.\n");
            break;
    }

    return;
}

void remove_item(Grocery* list, int* index){   //Takes the last struct and copies it to the slot which will be "removed" and then reallocates the memory for the array -1, keeping the old ID, to make things simple.

    int item;

    printf("Which item would you like to remove?\nID number: ");
    scanf("%d", &item);

    strcpy(list[item].grocery, list[*index].grocery);
    list[item].amount = list[*index].amount;
    strcpy(list[item].unit, list[*index].unit);

    list = realloc(list, (*index-1)*sizeof(Grocery));

    return ;
}

For the most part, the "Grocery read_from_file()" function works, but it returns only the first item instead of the list it correctly read.

  1. To return and assign (a pointer to) the whole list, change the call

      *list = read_from_file(file_pointer, list, &index); 

    to

      list = read_from_file(file_pointer, list, &index); 

    and the definition

     Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index){ … return *list; … return *list; } 

    to

     Grocery *read_from_file(FILE *file_pointer, Grocery *list, int *index) { … return list; … return list; } 
  2. To not leak the memory of the old list when it reads one from a file, insert free(list) before list = (Grocery*)calloc(*index, sizeof(Grocery)); or change that to

      list = realloc(list, *index * sizeof(Grocery)); 

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