Home > Software design >  C binary file handling
C binary file handling

Time:09-09

I'm not used to programm (Since i'm a newcomer) so I'd like to get some help with this project... I'm trying to make a maker/reader programm using binary files, structs and pointers but my programm crashes every time this and his process

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

struct Recipe{
    char name[30];
    char difficulty[30];
    double calories; 
};

void generate_file(FILE *in){
    fopen("recipe.bin", "wb");
    if(in == NULL){
        fprintf(stderr, "\nErro, o arquivo não pode ser aberto\n");
        exit(1);
    }
    
    struct Recipe *recipe = malloc(sizeof(struct Recipe));
    printf("Digite o nome da receita: ");
    gets(recipe->name);
    printf("Digite o nivel de dificuldade da receita: ");
    gets(recipe->difficulty);
    printf("Digite o número de calorias: ");
    scanf("%d", &recipe->calories);
    
    fwrite(&recipe, sizeof(struct Recipe), 1, in);
    
    if(fwrite != 0){
        printf("Arquivo salvo com sucesso!");
    }else{
        printf("Falha no salvamento de dados");
        exit(1);
    }
    
    fclose(in);
    exit(0);
}

int main(int argc, char* argv[]){
    
    FILE *in;
    generate_file(in);
}

CodePudding user response:

The program crashes because you pass uninitialized or wrong pointers to certain functions.

From top to bottom:

Change the declaration of generate_file so that it takes a filename and returns an integer, like this:

int generate_file(const char *filename)

Assign the result from fopen to in, like this:

FILE *in = fopen(filename, "wb");

Replace exit with return:

return 1;

Initialize the structure after creation with zeros, for easier troubleshooting:

memset(recipe, 0, sizeof(struct Recipe));

Replace %d when scanning calories with %lf:

scanf("%lf", &recipe->calories);

Do not dereference the recipe (replace &recipe with recipe) when calling fwrite - it already is a pointer. Assign result of fwrite function into a variable and then test the variable instead of the function pointer when checking how many items were written:

size_t written = fwrite(&recipe, sizeof(struct Recipe), 1, in);
if (written != 0) {

Again, replace exit with return and use a different value then before, so that you can distinguish the cause of the problem later:

return 2;

In main(), change the argument to the name of the file and use the result from called function:

int result = generate_file("recipe.bin");
return result;

Here is the complete code:

int generate_file(const char *filename) {
    FILE* in = fopen(filename, "wb");
    if(in == NULL) {
        fprintf(stderr, "\nErro, o arquivo não pode ser aberto\n");
        return 1;
    }
    
    struct Recipe *recipe = malloc(sizeof(struct Recipe));
    memset(recipe, 0, sizeof(struct Recipe));
    printf("Digite o nome da receita: ");
    gets(recipe->name);
    printf("Digite o nivel de dificuldade da receita: ");
    gets(recipe->difficulty);
    printf("Digite o número de calorias: ");
    scanf("%lf", &recipe->calories);
    
    size_t written = fwrite(recipe, sizeof(struct Recipe), 1, in);
    
    if(written != 0){
        printf("Arquivo salvo com sucesso!");
    }else{
        printf("Falha no salvamento de dados");
        return 2;
    }
    
    fclose(in);
    return 0;
}

int main(int argc, char* argv[]) {
    int result = generate_file("recipe.bin");
    return result;
}

CodePudding user response:

I guess you want to use in as your file? You don't assign the return value of fopen to in. in points to nothing, so using I/O functions such as fwrite on it will cause some errors.

in = fopen("recipe.bin", "wb");

Also, fwrite expects a pointer, not a pointer to a pointer, since recipe is already a pointer, you don't need to &. fwrite(const void *ptr..)

Side note: You should never use gets, it is not a safe function as it might cause an overflow. Use fgets instead.

  • Related