从C中的CSV文件中读取每次都返回相同的值

时间:2017-02-04 19:17:59

标签: c csv

我有一个值为

的csv文件
1,A,X
2,B,Y
3,C,Z

我必须逐行读取CSV文件并将其保存在Structure数组中。 每次在for循环中值都很好。但是在我打印数组的最后,只打印了最后一个值。 有人请告诉我我在哪里做逻辑错误?

struct proc
{
    char *x;
    char *y;
};

void main()
{
    fflush(stdin);
    fflush(stdout);

    const char s[2] = ",";
    char *token;
    int rows=0,i,tokenVal=0,rowCount=0;
    FILE *fpCount = fopen("data.csv","r");
    if(fpCount != NULL)
    {
        char lineCount[20];
        while(fgets(lineCount, sizeof lineCount, fpCount))
            rows++;
    }
    struct proc *pi[rows];
    for(i=0;i<rows;i++)
        pi[i] = (struct proc*) malloc(sizeof(struct proc));
    FILE *fp = fopen("data.csv", "r");
    if(fp != NULL)
    {
        char line[20];        
        while(fgets(line, sizeof line, fp) != NULL)
        {
            printf("Start rowCount = %d\t",rowCount);
            token = strtok(line, s);
            while(token!=NULL)
            {
                if(tokenVal==0)
                    {
                        pi[rowCount]->Id =token;
                    }
                if(tokenVal==1)
                {
                    pi[rowCount]->act = token;
                }
                printf("\n");
                tokenVal++;
                token = strtok(NULL,s);
            }

            tokenVal = 0;
            printf("end rowCount = %d\t",rowCount);
            rowCount++;
        }
        fclose(fp);
    } else {
        perror("data.csv");
    }
    printf("total %d",rowCount);
    int k=0;
    for(k=0;k<rowCount;k++)
    {
        printf(" %d = %s----%s",k,pi[k]->Id,pi[k]->act);
    }
}

2 个答案:

答案 0 :(得分:0)

printf(“%d =%s ----%s ----%s”,k,pi [k] - &gt; Id,pi [k] - &gt; act) 有四个数据 %d %S %S %S

但你只设置了三个 ķ PI [K] - &GT;标识 PI [K] - &GT;行为

答案 1 :(得分:0)

诊断

您面临的根本问题是您在结构中保存指向变量line的指针,但每个新行都会覆盖line中之前的内容,所以最后只有来自最后一行存在。你的数据线都是'形状'是偶然的;如果字段长度不同,那么你会得到更多有趣但同样错误的结果。

因此,您需要保存每个字段的副本,而不仅仅是指向字段的指针。使用POSIX函数strdup()的简单方法是使用POSIX函数What should main() return in C and C++?。如果您没有该功能,可以创建它:

char *strdup(const char *str)
{
    size_t len = strlen(str) + 1;
    char *rv = malloc(len);
    if (rv != 0)
        memmove(rv, str, len);  // or memcpy
    return rv;
}

您的代码无法编译;您的数据结构包含元素xy,但您的代码使用元素Idact。你使用指向你的struct proc的指针的VLA,但是分配一个结构数组是合理的,无论是作为VLA还是通过malloc()等。您应该检查内存分配 - 但是没有办法检查VLA(使用动态分配的一个原因)。您可以回放文件而不是重新打开它。 (使用变量保存文件名是个好主意,即使你只打开一次;它会使错误报告更好。另外,错误应该会停止程序,一般来说,尽管你确实使用了perror()重新打开操作失败 - 但是如果打开失败则不会。)您不需要两个数组来读取行。对输入线使用更长的缓冲区是个好主意。你应该释放动态分配的内存。另请参阅https://jsfiddle.net/7fo28qrd/;答案是int而不是void(除非你在Windows上)。

以下是您的代码的三种变体,上面列出的问题的各个方面或多或少已修复。

指针的VLA

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

struct proc
{
    char *x;
    char *y;
};

int main(void)
{
    const char datafile[] = "data.csv";
    const char csv_delim[] = ",\n";
    int rows = 0, rowCount = 0;
    FILE *fpCount = fopen(datafile, "r");

    if (fpCount == NULL)
    {
        fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
        exit(EXIT_FAILURE);
    }

    char lineCount[2000];
    while (fgets(lineCount, sizeof(lineCount), fpCount))
        rows++;
    fclose(fpCount);

    printf("Read %d rows from '%s'\n", rows, datafile);

    struct proc *pi[rows];
    for (int i = 0; i < rows; i++)
        pi[i] = (struct proc *)malloc(sizeof(struct proc));

    FILE *fp = fopen(datafile, "r");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
        exit(EXIT_FAILURE);
    }

    char line[2000];
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        printf("Start rowCount = %d\t", rowCount);
        int tokenVal = 0;
        char *token = strtok(line, csv_delim);
        while (token != NULL)
        {
            if (tokenVal == 0)
            {
                pi[rowCount]->x = strdup(token);
            }
            else if (tokenVal == 1)
            {
                pi[rowCount]->y = strdup(token);
            }
            printf("[%s]", token);
            tokenVal++;
            token = strtok(NULL, csv_delim);
        }
        printf("\tend rowCount = %d\n", rowCount);
        rowCount++;
    }

    fclose(fp);

    /* Data validation */
    printf("total %d\n", rowCount);
    for (int k = 0; k < rowCount; k++)
    {
        printf("%d = [%s]----[%s]\n", k, pi[k]->x, pi[k]->y);
    }

    /* Release allocated memory */
    for (int k = 0; k < rowCount; k++)
    {
        free(pi[k]->x);
        free(pi[k]->y);
        free(pi[k]);
    }

    return 0;
}

结构的VLA

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

struct proc
{
    char *x;
    char *y;
};

int main(void)
{
    const char datafile[] = "data.csv";
    const char csv_delim[] = ",\n";
    int rows = 0, rowCount = 0;
    FILE *fpCount = fopen(datafile, "r");

    if (fpCount == NULL)
    {
        fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
        exit(EXIT_FAILURE);
    }

    char lineCount[2000];
    while (fgets(lineCount, sizeof(lineCount), fpCount))
        rows++;
    fclose(fpCount);

    printf("Read %d rows from '%s'\n", rows, datafile);

    struct proc pi[rows];

    FILE *fp = fopen(datafile, "r");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
        exit(EXIT_FAILURE);
    }

    char line[2000];
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        printf("Start rowCount = %d\t", rowCount);
        int tokenVal = 0;
        char *token = strtok(line, csv_delim);
        while (token != NULL)
        {
            if (tokenVal == 0)
            {
                pi[rowCount].x = strdup(token);
            }
            else if (tokenVal == 1)
            {
                pi[rowCount].y = strdup(token);
            }
            printf("[%s]", token);
            tokenVal++;
            token = strtok(NULL, csv_delim);
        }
        printf("\tend rowCount = %d\n", rowCount);
        rowCount++;
    }

    fclose(fp);

    /* Data validation */
    printf("total %d\n", rowCount);
    for (int k = 0; k < rowCount; k++)
    {
        printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
    }

    /* Release allocated memory */
    for (int k = 0; k < rowCount; k++)
    {
        free(pi[k].x);
        free(pi[k].y);
    }

    return 0;
}

动态结构数组

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

struct proc
{
    char *x;
    char *y;
};

int main(void)
{
    const char datafile[] = "data.csv";
    const char csv_delim[] = ",\n";
    int num_rows = 0, rowCount = 0;
    FILE *fp = fopen(datafile, "r");

    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
        exit(EXIT_FAILURE);
    }

    char line[2000];
    while (fgets(line, sizeof(line), fp))
        num_rows++;
    rewind(fp);

    printf("Read %d rows from '%s'\n", num_rows, datafile);

    struct proc *pi = calloc(num_rows, sizeof(*pi));
    if (pi == 0)
    {
        fprintf(stderr, "Failed to allocate %zu bytes of memory\n", num_rows * sizeof(*pi));
        exit(EXIT_FAILURE);
    }

    while (fgets(line, sizeof(line), fp) != NULL)
    {
        printf("Start rowCount = %d\t", rowCount);
        int tokenVal = 0;
        char *token = strtok(line, csv_delim);
        while (token != NULL)
        {
            if (tokenVal == 0)
            {
                pi[rowCount].x = strdup(token);
                // null check
            }
            else if (tokenVal == 1)
            {
                pi[rowCount].y = strdup(token);
                // null check
            }
            printf("[%s]", token);
            tokenVal++;
            token = strtok(NULL, csv_delim);
        }
        printf("\tend rowCount = %d\n", rowCount);
        rowCount++;
    }

    fclose(fp);

    /* Data validation */
    printf("total %d\n", rowCount);
    for (int k = 0; k < rowCount; k++)
    {
        printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
    }

    /* Release allocated memory */
    for (int k = 0; k < rowCount; k++)
    {
        free(pi[k].x);
        free(pi[k].y);
    }
    free(pi);

    return 0;
}

给定一个数据文件:

1,A,X
2,B,Y
3,C,Z
3192-2146-9913,Abelone,Zoophyte

所有三个程序都产生相同的输出:

Read 4 rows from 'data.csv'
Start rowCount = 0  [1][A][X]   end rowCount = 0
Start rowCount = 1  [2][B][Y]   end rowCount = 1
Start rowCount = 2  [3][C][Z]   end rowCount = 2
Start rowCount = 3  [3192-2146-9913][Abelone][Zoophyte] end rowCount = 3
total 4
0 = [1]----[A]
1 = [2]----[B]
2 = [3]----[C]
3 = [3192-2146-9913]----[Abelone]