Home > Enterprise >  Typedef in C; How to pass structure objects to functions in C and use them to write/read to file?
Typedef in C; How to pass structure objects to functions in C and use them to write/read to file?

Time:11-26

I'm trying to pass a "dino" struct object that has been declared in C using typedef struct format. I'm then assigning values to this object, named d0, and then passing the whole object to a function, which is meant to write to a file in byte format, writing all of the parameters of d0. Then I am attempting to take this file, and then read to a new dino object, d1, and assign the values for each parameter to this new dino. When I run it, there are a few errors. Namely, my save_dino argument is incompatible. The save_dino function declaration uses dino *d and I'm just passing in d0. I don't understand exactly what I'm supposed to pass in instead of d0. Secondly, d is a pointer, and gcc is telling me I should have used -> instead of .

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

// your code here (define the dino struct)
// use typedef struct, not just struct

typedef struct Dino {
    double lat;
    double lng;
    char *name;
} dino;

void save_dino(dino *d, char *ofn)
{
    FILE *fp = fopen(ofn, "wb");
    fwrite(&d.lat, sizeof(double), 1, fp);
    fwrite(&d.lng, sizeof(double), 1, fp);
    fwrite(d.name, strlen(d.name), 1, fp);
    fclose(fp);
}

void load_dino(dino *d, char *ifn)
{
    FILE *fp = fopen(ifn, "rb");
    fread(d.lat, sizeof(double), 1, fp);
    fread(d.lng, sizeof(double), 1, fp);
    while(!feof(fp))
    {
        fscanf(fp, "%s", d.name);
    }
}

int main(int argc, char **argv)
{
    if(argc != 2)
        return 1;
    
    char *fn = argv[1];
    
    // create a dino struct and give it the following values:
    // latitude = 51.083332
    // longitude = -1.166667
    //name = "Aves indet."
    // do NOT hardcode the string length, get it with strlen() instead
    dino d0;
    d0.lat = 51.083332;
    d0.lng = -1.166667;
    strcpy(d0.name, "Aves indet.");
    
    // call save_dino() and save d0 to the given filename (fn)
    save_dino(d0, fn);
    
    dino d1;
    
    // call load_dino() and load the file you just saved into d1 (NOT d0)
    load_dino(d1, fn);
    
    printf("d1.lat %f\n", d1.lat);
    printf("d1.lng %f\n", d1.lng);
    printf("d1.name %s\n", d1.name);
    
    return 0;
}

This is my code.

CodePudding user response:

name is a pointer. Memory needs to be allocated to the pointer.
Save the length of name as part of the file. Reading the file will need the length to allocate, then the name can be read.

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

typedef struct Dino {
    double lat;
    double lng;
    char *name;
} dino;

void save_dino(dino *d, char *ofn)
{
    FILE *fp = fopen(ofn, "wb");
    fwrite(&d->lat, 1, sizeof(double), fp);
    fwrite(&d->lng, 1, sizeof(double), fp);
    size_t len = strlen ( d->name);
    fwrite(&len, 1, sizeof(size_t), fp);
    fwrite(d->name, 1, len, fp);
    fclose(fp);
}

void load_dino(dino *d, char *ifn)
{
    FILE *fp = fopen(ifn, "rb");
    fread(&d->lat, 1, sizeof(double), fp);
    fread(&d->lng, 1, sizeof(double), fp);
    size_t len = 0;
    fread(&len, 1, sizeof(size_t), fp);
    if ( NULL == ( d->name = malloc ( len   1))) {
        fprintf ( stderr, "problem malloc\n");
        fclose ( fp);
        return;
    }
    fread(d->name, 1, len, fp);
    d->name[len] = 0;
    fclose(fp);
}

int main(int argc, char **argv)
{
    if(argc != 2)
        return 1;

    char *fn = argv[1];

    // create a dino struct and give it the following values:
    // latitude = 51.083332
    // longitude = -1.166667
    //name = "Aves indet."
    // do NOT hardcode the string length, get it with strlen() instead
    dino d0;
    d0.lat = 51.083332;
    d0.lng = -1.166667;
    d0.name = strdup ( "Aves indet.");

    // call save_dino() and save d0 to the given filename (fn)
    save_dino(&d0, fn);
    free ( d0.name);

    dino d1 = { 0.0, 0.0, NULL};

    // call load_dino() and load the file you just saved into d1 (NOT d0)
    load_dino(&d1, fn);

    printf("d1.lat %f\n", d1.lat);
    printf("d1.lng %f\n", d1.lng);
    printf("d1.name %s\n", d1.name);
    free ( d1.name);

    return 0;
}

CodePudding user response:

Well first of all, we don't reference structs as objects, because on C89 we dont have the concept of classes, neither attributes.

So is better to treat it as a register or literally a struct.

Answering your question. It's better to save the entire struct, "typedefing" your dino as a name type, is a way to "measure" its memory size.

You can try something this way:

void save_dino(Dino *d, char *ofn) {
  FILE *fp; 
  if ( (fp = fopen(ofn, "wb")) == NULL ){
    return;
  }
  fwrite(d, sizeof(Dino), 1, fp);
  fclose(fp); 
}

void load_dino(Dino **d, char *ifn)
{
    FILE *fp;
    if ( (fp = fopen(ofn, "rb")) == NULL ){
       return;
    }
    fread(&(*d), sizeof(Dino), 1, fp);
    return;
}

In time, there are some considerations about your code. When coding on C, its forbidden to declare variables outside of declaration scope. So whenever you start a function, even main(), or any scope, you should first declare your variables. Another thing, try to always check the return of fopen function, as other OS handlers, these things are able to fail easily, so make your knots tighten. Specially when opening, its safe and avoid explosions... Its a good practice, when opening inside a function, to return int values to test if everything went well.

If there's any doubt left, message me.

  • Related