【问题标题】:saving a struct for post fetching保存结构以进行后期提取
【发布时间】:2024-05-01 16:00:03
【问题描述】:

我是 C 的新手。我有一个具有特定结构的 csv 文件。我创建了结构并从 csv 文件中读取数据并使用定义的结构打印它。但是,我不需要打印结构,而是需要保存它,以便访问它以供以后处理。到目前为止,我已经明白我需要使用动态内存分配,但我现在完全迷失了。任何线索都会非常有用。

输入文件如下,

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

到目前为止我的代码

#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);
}

【问题讨论】:

    标签: c struct dynamic-memory-allocation


    【解决方案1】:

    // 如何在此处将一些数据保存到内存中,以便稍后在 main 外部访问它,例如 somedata[i] 用于第 i 个结构。

    您可以使用 struct O_data 的数组,使用 malloc 然后 realloc 进行分配,然后使该数组具有未知数量的条目更长,直到您读取所有文件


    deserialize_dat中的警告

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

    indexunsigned 但是你使用%d,必须是%u,在中的printf中也是一样的主要的

    tmpp 未使用,如参数 separators


    提案可以是:

    #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);
    }
    

    编译和执行:

    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
    

    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)
    

    注意我realloc每次只在数组中添加一个条目,如果文件中有很多值,最好在中添加多个条目而不是一个条目需要时重新分配

    【讨论】:

    • 您好,感谢您的回复。我正在尝试您的建议,但我需要一些线索。我完全迷路了。
    • @dipaksanap 我用提案和执行编辑了我的答案。注意我将 printf 移动到您在文件中读取的循环之后以显示值已被记住
    • 嗨@bruno,效果很好!万分感谢。我只是有一个小问题,您提到在大数据的情况下添加几行。我只是添加(nelts + bignumber)。另外,有什么作用?空:数据;做 ?谢谢。
    • @dipaksanap 目前我知道每个循环都没有足够的空间,因为一个接一个地增长,如果更多你需要区分让我们说 allocatedNeltsusedNelts 知道何时需要重新分配(它们是相等的),是的 reallocallocatedNelts + number_greater_than_1