【问题标题】:Parsing .csv file into 2D array in C将.csv文件解析为C中的二维数组
【发布时间】:2017-04-26 21:46:12
【问题描述】:

我有一个 .csv 文件,内容如下:

SKU,Plant,Qty
40000,ca56,1245
40000,ca81,12553.3
40000,ca82,125.3
45000,ca62,0
45000,ca71,3
45000,ca78,54.9

注意:这是我的示例,但实际上它有大约 500,000 行和 3 列。

我正在尝试将这些条目转换为二维数组,以便随后可以操作数据。您会注意到,在我的示例中,我只是设置了一个小的 10x10 矩阵 A 来尝试让此示例运行,然后再进行实际操作。

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

const char *getfield(char *line, int num);

int main() {
    FILE *stream = fopen("input/input.csv", "r");
    char line[1000000];
    int A[10][10];
    int i, j = 0;

    //Zero matrix
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            A[i][j] = 0;
        }
    }

    for (i = 0; fgets(line, 1000000, stream); i++) {
        while (j < 10) {
            char *tmp = strdup(line);
            A[i][j] = getfield(tmp, j);
            free(tmp);
            j++;
        }
    }
    //print matrix
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            printf("%s\t", A[i][j]);
        }
        printf("\n");
    }
}

const char *getfield(char *line, int num) {
    const char *tok;
    for (tok = strtok(line, ",");
         tok && *tok;
         tok = strtok(NULL, ",\n"))
    {
        if (!--num)
            return tok;
    }
    return 0;
}

它只打印“空”错误,我相信我犯了与这一行的指针有关的错误:A[i][j] = getfield(tmp, j)。我只是不确定如何解决这个问题。

这项工作几乎完全基于这个问题:Read .CSV file in C。非常感谢您在适应此问题方面的任何帮助,因为自从我上次接触 C 或外部文件以来已经有几年了。

【问题讨论】:

  • 1) int A[10][10]; --> const char *A[10][10];
  • getfield() 不会进行任何复制,它只是切碎并返回tmp 的一部分。然后将tmp 的那部分分配给矩阵中的一个位置,然后释放tmp。 (正如@BLUEPIXY 指出的那样,它甚至没有被定义为保存字符串)如果你要将指针存储在A 中,你必须保持它们的分配状态,直到你完成它们作为初学者。 (我还没有读过这行代码,所以可能会有更多……)
  • 3) if (!--num) --> if (!num--)
  • 4) 您需要重置j。喜欢j = 0; while(j&lt;10){ 或使用for
  • @ebyrob 基本上这些问题大多是题外话。

标签: c arrays csv parsing pointers


【解决方案1】:

看起来评论者已经帮助您找到了代码中的一些错误。然而,这些问题非常根深蒂固。最大的问题之一是您使用的是字符串。字符串当然是字符数组;这意味着已经有一个维度在使用中。

使用这样的结构可能会更好:

struct csvTable
{
    char sku[10];
    char plant[10];
    char qty[10];
};

这还允许您将列设置为正确的数据类型(看起来 SKU 可能是 int,但我不知道上下文)。

这是该实现的一个示例。我为混乱道歉,它是根据我已经在做的事情即时改编的。

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

// Based on your estimate
// You could make this adaptive or dynamic

#define rowNum 500000

struct csvTable
{
    char sku[10];
    char plant[10];
    char qty[10];
};

// Declare table
struct csvTable table[rowNum];

int main()
{
    // Load file
    FILE* fp = fopen("demo.csv", "r");

    if (fp == NULL)
    {
        printf("Couldn't open file\n");
        return 0;
    }

    for (int counter = 0; counter < rowNum; counter++)
    {
        char entry[100];
        fgets(entry, 100, fp);

        char *sku = strtok(entry, ",");
        char *plant = strtok(NULL, ",");
        char *qty = strtok(NULL, ",");

        if (sku != NULL && plant != NULL && qty != NULL)
        {
            strcpy(table[counter].sku, sku);
            strcpy(table[counter].plant, plant);
            strcpy(table[counter].qty, qty);
        }
        else
        {
            strcpy(table[counter].sku, "\0");
            strcpy(table[counter].plant, "\0");
            strcpy(table[counter].qty, "\0");
        }
    }

    // Prove that the process worked
    for (int printCounter = 0; printCounter < rowNum; printCounter++)
    {
        printf("Row %d: column 1 = %s, column 2 = %s, column 3 = %s\n", 
            printCounter + 1, table[printCounter].sku, 
            table[printCounter].plant, table[printCounter].qty);
    }

    // Wait for keypress to exit
    getchar();

}

【讨论】:

    【解决方案2】:

    您的代码存在多个问题:

    • 在第二个循环中,您不会在 10 行之后停止读取文件,因此您会尝试将元素存储到 A 数组末尾之外。
    • 在while (j &lt; 10) 循环开始时,您不会将j 重置为0。 j 恰好在初始化循环结束时具有值 10,因此您实际上不会将任何内容存储到矩阵中。
    • 矩阵A 应该是char * 的二维数组,而不是int,或者可能是结构数组。

    这是一个分配了结构数组的更简单的版本:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct item_t {
        char SKU[20];
        char Plant[20];
        char Qty[20];
    };
    
    int main(void) {
        FILE *stream = fopen("input/input.csv", "r");
        char line[200];
        int size = 0, len = 0, i, c;
        item_t *A = NULL;
    
        if (stream) {
            while (fgets(line, sizeof(line), stream)) {
                if (len == size) {
                    size = size ? size * 2 : 1000;
                    A = realloc(A, sizeof(*A) * size);
                    if (A == NULL) {
                        fprintf(stderr, "out of memory for %d items\n", size);
                        return 1;
                    }
                }
                if (sscanf(line, "%19[^,\n],%19[^,\n],%19[^,\n]%c",
                           A[len].SKU, A[len].Plant, A[len].Qty, &c) != 4
                ||  c != '\n') {
                    fprintf(stderr, "invalid format: %s\n, line);
                } else {
                    len++;
                }
            }
            fclose(stream);
    
            //print matrix
            for (i = 0; i < len; i++) {
                printf("%s,%s,%s\n", A[i].SKU, A[i].Plant, A[i].Qty);
            }
            free(A);
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      相关资源
      最近更新 更多