Search code examples
cstructdynamic-memory-allocation

saving a struct for post fetching


I am newbie to C. I have a csv file with a particular structure. I created struct and and read the data from csv file and print it using defined struct. However, instead of printing the struct I need to save it so I an access it for later processing. So far, I have understood I need to use dynamic memory allocation but I am totally lost right now. any leads would be really useful.

The inputfile as follows,

2,33.1609992980957,26.59000015258789,8.003999710083008
5,15.85200023651123,13.036999702453613,31.801000595092773
8,10.907999992370605,32.000999450683594,1.8459999561309814
11,28.3700008392334,31.650999069213867,13.107999801635742
14,7.046000003814697,23.5939998626709,6.254000186920166

My code so far

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

struct O_data
{
   unsigned int index;
   float x;
   float y;
   float z;
};

struct O_data * deserialize_data(struct O_data *data, const char *input,   const char *separators)
{
   char *p;
   struct O_data tmp;
   if(sscanf(input, "%d,%f,%f,%f", &data->index, &data->x, &data->y, &data->z) != 7)
   return NULL;
   return data;
}

int  main(int argc, char *argv[])
{
   FILE *stream;
   char *line = NULL;
   size_t len = 0;
   ssize_t nread;
   struct O_data somedata;
   if (argc != 2) {
       fprintf(stderr, "Usage: %s <file>\n", argv[0]);
       exit(EXIT_FAILURE);
   }
   stream = fopen(argv[1], "r");
   if (stream == NULL) {
       perror("fopen");
       exit(EXIT_FAILURE);
   }
   while ((nread = getline(&line, &len, stream)) != -1) {
       deserialize_data(&somedata, line, ",");
// How do I save some data to memory here to access it later like somedata[i] for ith struct later outside main. 
       printf("index: %d, x: %f, y: %f, z: %f\n", somedata.index, somedata.x, somedata.y, somedata.z);
   }
   free(line);
   fclose(stream);
   exit(EXIT_SUCCESS);
}

Solution

  • // How do I save some data to memory here to access it later like somedata[i] for ith struct later outside main.

    you can use an array of struct O_data using malloc then realloc to allocate then make longer that array having an unknown number of entries until you read all the file


    Warning in deserialize_dat

    sscanf(input, "%d,%f,%f,%f", &data->index, &data->x, &data->y, &data->z)
    

    index is unsigned but you use %d, must be %u, it is the same in printf in main

    tmp and p are unused, like the parameter separators


    A proposal can be :

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct O_data
    {
       unsigned int index;
       float x;
       float y;
       float z;
    };
    
    struct O_data * deserialize_data(struct O_data *data, const char *input)
    {
       return (sscanf(input, "%u,%f,%f,%f", &data->index, &data->x, &data->y, &data->z) != 7) 
         ? NULL : data;
    }
    
    int  main(int argc, char *argv[])
    {
       FILE *stream;
       char *line = NULL;
       size_t len = 0;
       ssize_t nread;
       struct O_data * somedata = NULL;
       size_t nelts = 0;
    
       if (argc != 2) {
           fprintf(stderr, "Usage: %s <file>\n", argv[0]);
           exit(EXIT_FAILURE);
       }
       stream = fopen(argv[1], "r");
       if (stream == NULL) {
           perror("fopen");
           exit(EXIT_FAILURE);
       }
       while ((nread = getline(&line, &len, stream)) != -1) {
         if ((somedata = realloc(somedata, (nelts + 1) * sizeof(struct O_data))) == NULL) {
           fprintf(stderr, "error not enough memory");
           exit(EXIT_FAILURE);
         }
         deserialize_data(&somedata[nelts++], line);
       }
       free(line);
       fclose(stream);
    
       /* print and free */
       for (size_t i = 0; i != nelts; ++i)
         printf("index: %u, x: %f, y: %f, z: %f\n",
                somedata[i].index, somedata[i].x, somedata[i].y, somedata[i].z);
    
       free(somedata);
    
       exit(EXIT_SUCCESS);
    }
    

    Compilation and execution :

    pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra a.c
    pi@raspberrypi:/tmp $ cat f
    2,33.1609992980957,26.59000015258789,8.003999710083008
    5,15.85200023651123,13.036999702453613,31.801000595092773
    8,10.907999992370605,32.000999450683594,1.8459999561309814
    11,28.3700008392334,31.650999069213867,13.107999801635742
    14,7.046000003814697,23.5939998626709,6.254000186920166
    pi@raspberrypi:/tmp $ ./a.out f
    index: 2, x: 33.160999, y: 26.590000, z: 8.004000
    index: 5, x: 15.852000, y: 13.037000, z: 31.801001
    index: 8, x: 10.908000, y: 32.000999, z: 1.846000
    index: 11, x: 28.370001, y: 31.650999, z: 13.108000
    index: 14, x: 7.046000, y: 23.594000, z: 6.254000
    

    Execution under valgrind :

    pi@raspberrypi:/tmp $ valgrind ./a.out f
    ==2439== Memcheck, a memory error detector
    ==2439== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==2439== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
    ==2439== Command: ./a.out f
    ==2439== 
    index: 2, x: 33.160999, y: 26.590000, z: 8.004000
    index: 5, x: 15.852000, y: 13.037000, z: 31.801001
    index: 8, x: 10.908000, y: 32.000999, z: 1.846000
    index: 11, x: 28.370001, y: 31.650999, z: 13.108000
    index: 14, x: 7.046000, y: 23.594000, z: 6.254000
    ==2439== 
    ==2439== HEAP SUMMARY:
    ==2439==     in use at exit: 0 bytes in 0 blocks
    ==2439==   total heap usage: 9 allocs, 9 frees, 5,832 bytes allocated
    ==2439== 
    ==2439== All heap blocks were freed -- no leaks are possible
    ==2439== 
    ==2439== For counts of detected and suppressed errors, rerun with: -v
    ==2439== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
    

    Note I realloc adding only one entry in the array each time, if there are a lot of values in the file it can be better to add several entries rather than just one in the realloc when needed