【问题标题】:.txt vs .csv parsing C.txt 与 .csv 解析 C
【发布时间】:2016-04-07 19:14:50
【问题描述】:

我创建了一个代码,该代码将使用 C 将 .txt 文件解析为双精度数组。我的 .txt 文件已格式化,因此每个点都由 "," 分隔。现在我想让这段代码解析相同的数据,但来自 .csv 文件。当我更改文件类型时,我收到分段错误。

为什么会发生这种情况?我是否误以为这两种文档类型将以相同的方式阅读?

这篇文章的主要问题是,读取 .txt 和 .csv 有什么区别?

/* 
* Calibration File Read Test
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main ()
{
    FILE *myfile = fopen ( "BarEast.txt", "r" );
    /* I want to change this file type to .csv */

    /* opening file for reading */
    if(myfile == NULL) 
    {
        printf("Error opening file");
        return(-1);
    }

    int i = 0;
    int j, k;

    char *result[361] = {0};
    char line[10];
    char *value;

    while(fgets(line, sizeof(line), myfile))
    {
        value = strtok(line, ",");
        result[i] = malloc(strlen(value) + 1);
        strcpy(result[i], value); 
        i++;
    }

    double val;
    double cal[361] = {0};

    for(k = 0; k < 361; k++)
    {
        val = atof(result[k]);
        cal[k] = val;
    }

    for(j = 0; j < 361; j++)
    {
        printf("Element[%d] = %f\n", j, cal[j]);
    }
    fclose(myfile);
    return 0;

}

【问题讨论】:

  • 只需使用sscanf 从支持某种正则表达式的字符串中扫描,请阅读此处:cplusplus.com/reference/cstdio/scanf
  • 我建议您比较您的 .txt 和 .csv 文件。我认为除了文件扩展名之外,它们在所有方面都应该相同,如果您的代码适用于其中一个,它应该适用于另一个。
  • Don't use Strcpy 如果您阅读了man page for strcpy 中的注释,就会明白为什么要远离它。
  • 问题不在于更改文件名,问题更确定,因为您的代码存在内存问题,这些问题由 .csv 文件的不同内容揭示。使用valgrind 或类似工具来找到它们。

标签: c parsing csv


【解决方案1】:

问题不在于文件名,而在于文件的内容不同。不同的内容暴露了代码中的内存问题。

我的目光立刻转向了无处不在的硬编码361。这假设输入文件中有 361 行,并且存在您的段错误。当val = atof(result[k]); 离开result 数组时,它发生在第40 行(使用valgrind 标识)。在 C 中,硬编码大小是非常诱人。不要这样做,尤其是输入,是你不能依赖的拐杖。

相反,代码必须适应文件中的字段数和行数。您可以使用realloc 编写您自己的动态数组代码,但是有很多 C 库可以为您执行此操作,而且效果更好。我联系GLib 了解基本信息。

另一个问题是您只为每行分配了 10 个字节。这是非常小的。这意味着fgets 会不断离开line,如果它超过 9 个字符(它将是)。从输入读取时任何类型的静态内存分配都是一个问题。使用getline 而不是fgets 可以避免每行分配多少内存的问题。 getline 为您解决这个问题。小心,getline 会重复使用line,所以如果你要更改line,你需要先strdup

/* 
* Calibration File Read Test
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>

int main (int argc, char **argv)
{
    /* Check we got the right number of arguments. */
    if( argc != 2 ) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return -1;
    }

    /* Open the file */
    FILE *fp = fopen ( argv[1], "r" );
    if(fp == NULL) 
    {
        fprintf(stderr, "Error opening file %s for reading.\n", argv[1]);
        return(-1);
    }

    /* A dynamic array which will grow as needed */
    GArray *result = g_array_new(TRUE, TRUE, sizeof(char *));

    /* Read each line using getline which does the line memory allocation
       for you. No buffer overflow to worry about. */
    char *line = NULL;
    size_t linecap = 0;
    while(getline(&line, &linecap, fp) > 0) {
        /* This will only read the first cell. Exercise left for the reader. */
        char *value = strtok(line, ",");
        if( value == NULL ) {
            fprintf(stderr, "Could not parse %s\n", line);
            continue;
        }

        char *field = malloc(strlen(value) + 1);
        strcpy(field, value);

        g_array_append_val(result, field);
    }

    free(line);
    fclose(fp);

    /* Iterate through the array using result->len to know the length */
    for(int i = 0; i < result->len; i++)
    {
        printf("Element[%d] = %s\n", i, g_array_index(result, char *, i));
    }

    /* Free the array */
    g_array_free(result, TRUE);

    return 0;

}

我已经删除了atof 转换,因为它分散了主要问题的注意力。如果你愿意,你可以把它放回去。

这仍然存在它只读取每行的第一个单元格的问题。我把这个问题留给你解决。

【讨论】:

    【解决方案2】:

    您在此代码中的转换 atof

    for(k = 0; k < 361; k++)
    {
        val = atof(result[k]);
        cal[k] = val;
    }
    

    超出数组“结果”的范围
    只有当你有数据要放入结果数组中时,才会为结果数组中的元素分配内存

    result[i] = malloc(strlen(value) + 1);

    如果创建的记录少于 361 条,则您正在从未分配的内存中读取 - 因此会出现错误。

    您需要记录已读入的结果数量,然后使用该值确保在处理结果数组时保持在范围内。

    根据文件扩展名,文件之间没有区别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-02
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 2011-12-12
      • 2016-02-28
      相关资源
      最近更新 更多