【问题标题】:C programming - Reading CSV fileC 编程 - 读取 CSV 文件
【发布时间】:2016-01-13 17:33:51
【问题描述】:

我目前在从 CSV 文件读取数据时遇到问题。

我认为代码几乎可以正常工作。但是,打印输出显示了一些奇怪的字符,如下所示(输出 9-11)。

你知道这里发生了什么吗?我只是想摆脱这些奇怪的字符,以便我可以相应地处理导入的数据。

或者,如果您对我的编码风格有任何反馈,如果您不介意,请与我分享。

输出:

Obsns size is 150 and feat size is 4.
1. 5.100000, 3.500000, 1.400000, 0.200000, Iris-setosa
2. 4.900000, 3.000000, 1.400000, 0.200000, Iris-setosa
3. 4.700000, 3.200000, 1.300000, 0.200000, Iris-setosa
4. 4.600000, 3.100000, 1.500000, 0.200000, Iris-setosa
5. 5.000000, 3.600000, 1.400000, 0.200000, Iris-setosa
6. 5.400000, 3.900000, 1.700000, 0.400000, Iris-setosa
7. 4.600000, 3.400000, 1.400000, 0.300000, Iris-setosa
8. 5.000000, 3.400000, 1.500000, 0.200000, Iris-setosa
9. 4.400000, 2.900000, 1.400000, 0.200000, ��L>-setosa
10. 4.900000, 3.100000, 1.500000, 0.100000, Iris���=osa
11. 5.400000, 3.700000, 1.500000, 0.200000, Iris-set��L>
12. 4.800000, 3.400000, 1.600000, 0.200000, Iris-setosa
13. 4.800000, 3.000000, 1.400000, 0.100000, Iris-setosa
14. 4.300000, 3.000000, 1.100000, 0.100000, Iris-setosa

代码:

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

int checkObsnsSize(char *dataFileName);
void readIris();

int main() {
    readIris();
    return 0;
}

void readIris() {    
    int featSize = 4;
    char *dataFileName = "iris.data";
    int obsnsSize = checkObsnsSize(dataFileName);
    float feat[featSize][obsnsSize];
    int label[obsnsSize];
    memset(feat, 0, featSize * obsnsSize * sizeof(float));
    memset(label, 0, obsnsSize * sizeof(int));

    printf("Obsns size is %d and feat size is %d.\n", obsnsSize, featSize);

    FILE *fpDataFile = fopen(dataFileName, "r");   
    if (!fpDataFile) {
        printf("Missing input file: %s\n", dataFileName);
        exit(1);
    }

    int index = 0;
    while (!feof(fpDataFile)) {
        char line[1024];
        char flowerType[20];

        fgets(line, 1024, fpDataFile);

        sscanf(line, "%f,%f,%f,%f,%[^\n]",
               &feat[1][index], &feat[2][index],
               &feat[3][index], &feat[4][index], flowerType);
        printf("%d. %f, %f, %f, %f, %s\n", ((int)index + 1),
               feat[1][index], feat[2][index],
               feat[3][index], feat[4][index], flowerType);
        index++;
    }
    fclose(fpDataFile);
}

int checkObsnsSize(char *dataFileName) {
    int obsnsSize = 0;
    char line[1024];

    FILE *fpDataFile = fopen(dataFileName, "r");
    if (!fpDataFile) {
        printf("Missing input file: %s\n", dataFileName);
        exit(1);
    }
    while (!feof(fpDataFile)) {
        fgets(line, 1024, fpDataFile);
        obsnsSize++;
    }
    fclose(fpDataFile);
    return obsnsSize;
}

【问题讨论】:

  • 顺便说一句,我在 Linux 上尝试了不同的编译器,但仍然遇到同样的错误。所以我认为上述问题与编译器的选择无关。
  • 请提供您的 CSV 文件。我使用从输出创建的 CSV 文件运行您的代码,程序似乎按预期运行。
  • 感谢 @chqrlie 帮助我重新格式化代码以提高可读性。

标签: c csv file-io import-from-csv


【解决方案1】:
sscanf(line, "%f,%f,%f,%f,%[^\n]", &feat[1][index], &feat[2][index],
         &feat[3][index], &feat[4][index], flowerType);
printf("%d. %f, %f, %f, %f, %s\n", ((int) index+1), feat[1][index], feat[2][index],
         feat[3][index], feat[4][index], flowerType);

在这两行中,您在&amp;feat[4][index] 处访问索引越界。这会导致未定义的行为

由于数组的声明是

 float feat[featSize][obsnsSize];     //where featSize is 4 

所以你可以从0访问索引34数组索引从0)。

【讨论】:

  • 你说的太对了。我把你指定的值减1后问题就解决了。谢谢ameyCU!
  • @FrankPuk 是的,那是因为您在无效的内存位置写入。如果您声明一个大小为 n 的数组,并且您可以访问从 0n-1 的索引。
【解决方案2】:

总而言之,正确的代码如下所示:

1- 使用 fgets() 返回值来确定文件何时被完全读取。
2- 从索引 0 开始读入数组
3- 检查 sscanf() 的返回值。

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

int checkObsnsSize(char * dataFileName);
void readIris ();

int main () {
    readIris();
    return 0;
}

void readIris() {

    int featSize = 4;

    char *dataFileName = "iris.data";
    int obsnsSize = checkObsnsSize(dataFileName);
    float feat[featSize][obsnsSize];
    int label[obsnsSize];
    memset(feat, 0, featSize*obsnsSize*sizeof(float));
    memset(label, 0, obsnsSize*sizeof(int));

    printf("Obsns size is %d and feat size is %d.\n", obsnsSize, featSize);

    FILE *fpDataFile = fopen(dataFileName,"r");

    if (!fpDataFile) {
        printf("Missing input file: %s\n", dataFileName);
        exit(1);
    }

    int index = 0;
    char line[1024]; char flowerType[20];

    while (fgets(line, 1024, fpDataFile))
    {
        if( 5 == sscanf(line, "%f,%f,%f,%f,%19[^\n]", &feat[0][index], &feat[1][index], &feat[2][index], &feat[3][index], flowerType))
        {
            printf("%d. %f, %f, %f, %f, %s\n", ((int) index+1), feat[0][index], feat[1][index], feat[2][index], feat[3][index], flowerType);
            index++;
        }
    }
    fclose(fpDataFile);
}

int checkObsnsSize(char * dataFileName) {

    int obsnsSize = 0;
    char line[1024];

    FILE *fpDataFile = fopen(dataFileName,"r");
    if (!fpDataFile) {
            printf("Missing input file: %s\n", dataFileName);
            exit(1);
        }
    while (!feof(fpDataFile)) {
        fgets(line, 1024, fpDataFile);
        obsnsSize++;
    }
    fclose(fpDataFile);
    return obsnsSize;
}

【讨论】:

  • 使用"%19[^\n]" 比使用%[^\n] 更好地防止缓冲区溢出 - 尽管这仍然不能检测行上的额外文本。
  • 同样不要在checkObsnsSize()中使用while (!feof(fpDataFile)),而是使用while (fgets(line, 1024, fpDataFile))
【解决方案3】:

有几点:

  • 不要检查feof,而是检查返回值fgets()

    while (!feof(fpDataFile)) {
    
  • 始终检查sscanf()的返回值。

  • 您的索引应该从 0 而不是 1 开始(索引 4 超出范围):

    sscanf(line, "%f,%f,%f,%f,%[^\n]",
           &feat[0][index], &feat[1][index],
           &feat[2][index], &feat[3][index], flowerType);
    printf("%d. %f, %f, %f, %f, %s\n", ((int)index + 1),
           feat[0][index], feat[1][index],
           feat[2][index], feat[3][index], flowerType);
    
  • 正如@chqrlie 所说:使用%19[^\n] 来避免溢出,因为flowerType 的大小只有20

    sscanf(line, "%f,%f,%f,%f,%19[^\n]",
           &feat[0][index], &feat[1][index],
           &feat[2][index], &feat[3][index], flowerType);
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2018-01-20
    • 1970-01-01
    • 2017-10-19
    • 2012-12-21
    • 1970-01-01
    • 2018-05-24
    相关资源
    最近更新 更多