使用 C 和动态分配从 CSV 读取和保存值

用户8506163

底部的编辑(我把它写成一个编辑而不是它自己的问题,因为它是如此相关):

我正在编写一个 CSV 阅读器,它应该将所有值保存为大型多维数组中的字符。在之前的帖子中,我被警告过我的精简代码过于模糊,所以我将发布更多。我想为它的长度道歉,因为我仍在尝试衡量这个网站上合适的长度是什么样的。

最终,这个程序将成为我正在创建的头文件中的头条新闻,以执行数据分析。我用于这个程序的头文件是:

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

我遇到的问题是阅读器似乎在名为 read_csv() 的函数中工作。我知道这是因为 printf() 语句放置在该函数中。当我 printf() main() 中的多维字符数组“缓冲区”时,数据显示不正确。

在 main() 中,第一列会正确打印,但接下来的三列不会。此外,我的目标是能够读取任何带有最多 20 个字符的单元格的 MxN CSV 文件。使用 malloc() 创建通用代码是我在此任务中的下一个目标。

我的 main() 结构如下:

int main(){

  FILE *f;
  char fname[20];
  int i, j;

  printf("enter name of csv file : ") ;
  scanf("%s",fname) ;       

  f = fopen(fname, "r");

  //find row/col
  int find_c_r[2];
  int * pfrc = &find_c_r[0];
  pfrc = find_col_row(f);
  printf("Find_c_r[0] = %d \t Find_c_r[1] = %d\n", *pfrc, *(pfrc+1));

  int numCol = *pfrc;
  int numRow = *(pfrc+1);

  char buffer[50][50][20];// ideally size buffer[numCol][numRow][20]

  //sets all values to NULL
  for(j = 0 ; j < 50 ; j++){
    for(i = 0 ; i < 10 ; i++){   
      memset(buffer[i][j],'\0', 20);
    }
  }

  read_csv(f, numCol, numRow, buffer); 
  /////
  printf("\n\n");

 for(j = 0 ; j < numRow ; j++){
    for(i = 0 ; i < numCol; i++){      
      printf("[%d][%d]",i, j);
      printf("_%s_  ",buffer[i][j]);
    } 
    printf("\n");
  }

  printf("END OF PROGRAM.\n");
 }

其中一部分是我的数组“缓冲区”的动态分配。我不太确定如何以这种格式 malloc() 。

main() 调用的第一个函数是 find_col_row(FILE *f)。它可以正常工作,但人们在问题中要求提供更多我的代码。它返回一个指向 int 数组的指针,该数组保存正在读取的 CSV 文件中的列数和行数:

int * find_col_row(FILE *f){
 //Find numCol and numRow
  int numCol, numRow;
  char c;
  int new_line= 0;
  int comma = 0;
  int z = 0;
  numCol = 0;
  numRow = 0;
  while (c != EOF) {
    c = fgetc(f) ; 
    if(c == ','){ //WORDS MUST BE SEPARATED BY COMMAS
      comma++;
    }
    if(c == ';'){ //LINES MUST BE SEPARATED BY SEMI-COLONS
      new_line++;
      if(numCol == 0){
         numCol = comma + 1;
      }
    } 
  }


  numRow = new_line - 1;

  int a[2] = {numCol, numRow};
  int * pa = &a[0];

  return pa;
}

被调用的第二个函数是 read_csv(...)。此函数的目标是“读取”CSV 文件并“保存”多维字符数组“缓冲区”中每个单元格的值:

void read_csv(FILE *f, int numCol, int numRow, char buffer[numCol][numRow][20])  //cells split by ',', row split by ';'
{
  char fname[100];
  int i = 0, j = 0;
  int c = 0,n = 0, z = 0;

  if (f == NULL) {
    printf("can't open file, %s\n", fname) ;
    exit(1) ;
  }

  n = 0 ;

  fseek(f, 0, SEEK_SET); //starts reading the file from the start
  c = fgetc(f) ;

  i = 0;
  j = 0;


  char temp[20];
  memset(temp, '\0', 20);
  int tc = 0; //temp counter
  int mv_temp = 0; //this aids in removing the first character if == ' '
  temp[tc] = c;
  while (c != EOF) {

    if(c == ','){
      if(temp[0] == ' '){
         for(mv_temp = 0 ; mv_temp < tc ; mv_temp++){
           temp[mv_temp] = temp[mv_temp + 1];
         }
      }
      strncpy(buffer[i][j], temp, 20);
      i++; 
      tc = 0;
      memset(temp, '\0', 20);
    }else if(c == ';'){
      if(temp[0] == ' '){
         for(mv_temp = 0 ; mv_temp < tc ; mv_temp++){
           temp[mv_temp] = temp[mv_temp + 1];
         }
      }
      strncpy(buffer[i][j], temp, 20);
      j++;
      i = 0;
      tc = 0;
      memset(temp, '\0', 20);
       c = fgetc(f);

    }else{
      temp[tc] = c;
      tc++;
    }
    c = fgetc(f);    
  }  /////while loop over


  for(j = 0 ; j < numRow ; j++){
    for(i = 0 ; i < numCol; i++){      
      printf("[%d][%d]",i, j);
      printf("_%s_  ",buffer[i][j]);
    } 
    printf("\n");
  }

}

没有尝试使用任何其他 CSV 文件运行此程序,这是我使用的 CSV。运行程序时,第一步将是 scanf() 文件的名称。我叫它

simp.csv

作为参考,此数据指的是美式足球的基本数据:阵型、阵型变化、向下、距离。该文件如下所示:

OFF_FORM,FORM_VAR, DN, DIST;
DEUCE,RIGHT, 1, 10;
DEUCE,LEFT, 2, 7;
TRIO,RIGHT, 3, 3;
TREY,LEFT, 1, 10;
TRIO,RODDY, 1, 10;
TREY,LION, 2, 3;
DEEP,LEFT, 1, 10;
DEUCE,LION, 2, 15;
DEUCE,RIGHT, 3, 4;
DEEP,RODDY, 1, 10;
TREY,RIGHT, 1, 10;
TRIO,RAM, 2, 8;
TRIO,RAM, 3, 8;
DEEP,ROCK, 1, 10;
DEUCE,LION, 1, 10;
TRIO,LOUIE, 1, 10;
TRIO,RIGHT, 2,4;
DEUCE,RIGHT, 3, 6;
DEUCE,LION, 4, 2;
TREY,LION,1,10;

再次,我为问题的长度道歉。我希望我提供了足够的信息,以便提供帮助。作为一名年轻/新手程序员,我愿意接受任何和所有反馈。如果您能回答我的问题并指出优化我的代码以提高工作效率的方法,我将不胜感激。

////////////////////////////////////////////////// /////////////

编辑:

@BLUEPIXY 在他们的回答中共享的代码运行良好。现在,我只是想把它变成一个基本的头文件,我不确定如何修改我看到的一些问题。我对代码所做的只是更改函数的名称并将它们传输到头文件中。

#ifndef bp_csv_reader
#define bp_csv_reader    

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>

//https://tools.ietf.org/html/rfc4180
char *csv_get_field(FILE *fp, char separator, int *state)

char ***csv_read(const char *filename, size_t *rows, size_t *cols)

char *csv_trim(char *s)

#endif

csv.c 看起来像:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "csv.h"

//https://tools.ietf.org/html/rfc4180
char *csv_get_field(FILE *fp, char separator, int *state){
    int ch = fgetc(fp);

    if(ch == EOF)
        return NULL;

    size_t size = 1, index = 0;
    char *field = malloc(size);
    bool quoted_in = false;

    for(;ch != EOF; ch = fgetc(fp)){
        if(ch == '"'){
            if(quoted_in){
                int prefetch = fgetc(fp);
                if(prefetch == '"'){
                    ch = prefetch;
                } else {
                    quoted_in = false;
                    ungetc(prefetch, fp);
                    continue;
                }
            } else {
                quoted_in = true;
                continue;
            }
        } else if(!quoted_in && (ch == separator || ch == '\n')){
            break;
        }
        field[index++] = ch;
        char *temp = realloc(field, ++size);
        if(!temp){
            perror("realloc:");
            free(field);
            exit(EXIT_FAILURE);
        }
        field = temp;
    }
    field[index] = 0;
    *state = ch;
    if(quoted_in){
        fprintf(stderr, "The quotes is not closed.\n");
        free(field);
        return NULL;
    }
    return field;
}

char ***csv_read(const char *filename, size_t *rows, size_t *cols){
    *rows = *cols = 0;

    FILE *fp = fopen(filename, "r");
    if(!fp){
        fprintf(stderr, "%s can't open in %s\n", filename, __func__);
        perror("fopen");
        return NULL;
    }


    char *field;
    int state;
    size_t r = 0, c = 0;
    char ***mat = NULL;
    void *temp;

    while(field = csv_get_field(fp, ',', &state)){
        if(c == 0){
            mat = realloc(mat, (r + 1)*sizeof(*mat));
            if(!mat){
                fprintf(stderr, "realloc failed in %s\n", __func__);
                exit(EXIT_FAILURE);
            }
            mat[r] = NULL;
        }
        mat[r] = realloc(mat[r], (c + 1)*sizeof(**mat));
        if(!mat[r]){
            fprintf(stderr, "realloc failed in %s\n", __func__);
            exit(EXIT_FAILURE);
        }
        mat[r][c++] = field;
        if(state == '\n' || state == EOF){
            if(*cols == 0){
                *cols = c;
            } else if(c != *cols){
                fprintf(stderr, "line %zu doesn't match number of columns in %s\n", r, filename);
                exit(EXIT_FAILURE);
            }
            c  = 0;
            *rows = ++r;
        }
    }
    fclose(fp);

    return mat;
}

#include <ctype.h>

char *csv_trim(char *s){
    if(!s || !*s)
        return s;

    char *from, *to;

    for(from = s; *from && isspace((unsigned char)*from); ++from);
    for(to = s; *from;){
        *to++ = *from++;
    }
    *to = 0;
    while(s != to && isspace((unsigned char)to[-1])){
        *--to = 0;
    }
    return s;
}

调用它的代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <csv.h>


int main(void){
    size_t rows, cols;


    char ***mat = csv_read("simp.csv", &rows, &cols);

    size_t r, c;

    for(r = 0; r < rows; ++r){
        for(c = 0; c < cols; ++c){
            if(c)
                putchar(',');
            printf("%s", csv_trim(mat[r][c]));
            free(mat[r][c]);
        }
        puts("");
        free(mat[r]);
    }
    free(mat);
    return 0;
}

我不知道为什么我会遇到我遇到的错误。我得到的代码在它自己的文件中完美运行。直到我将它们放入头文件中才出现问题。这就是我在终端中编译的方式:

 acom test_csv.c csv.c -I. csv.h

这些是我看到的错误。

In file included from test_cesv.c:5:0:
./csv.h: In function ‘csv_get_field’:
./csv.h:15:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘char’
 char *csv_trim(char *s)
 ^
test_cesv.c:142:1: error: expected ‘{’ at end of input
 }
 ^
In file included from csv.c:5:0:
csv.h: In function ‘csv_get_field’:
csv.h:15:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘char’
 char *csv_trim(char *s)
 ^
csv.c:55:67: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
 char ***csv_read(const char *filename, size_t *rows, size_t *cols){
                                                                   ^
csv.c:105:24: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
 char *csv_trim(char *s){
                        ^
csv.c:120:1: error: expected ‘{’ at end of input
 }
 ^
csv.h: In function ‘csv_get_field’:
csv.h:15:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘char’
 char *csv_trim(char *s)
 ^
蓝精灵

试试这个

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

//https://tools.ietf.org/html/rfc4180
char *getCSVField(FILE *fp, char separator, int *state){
    int ch = fgetc(fp);

    if(ch == EOF)
        return NULL;

    size_t size = 1, index = 0;
    char *field = malloc(size);
    bool quoted_in = false;

    for(;ch != EOF; ch = fgetc(fp)){
        if(ch == '"'){
            if(quoted_in){
                int prefetch = fgetc(fp);
                if(prefetch == '"'){
                    ch = prefetch;
                } else {
                    quoted_in = false;
                    ungetc(prefetch, fp);
                    continue;
                }
            } else {
                quoted_in = true;
                continue;
            }
        } else if(!quoted_in && (ch == separator || ch == '\n')){
            break;
        }
        field[index++] = ch;
        char *temp = realloc(field, ++size);
        if(!temp){
            perror("realloc:");
            free(field);
            exit(EXIT_FAILURE);
        }
        field = temp;
    }
    field[index] = 0;
    *state = ch;
    if(quoted_in){
        fprintf(stderr, "The quotes is not closed.\n");
        free(field);
        return NULL;
    }
    return field;
}

char ***read_csv(const char *filename, size_t *rows, size_t *cols){
    *rows = *cols = 0;

    FILE *fp = fopen(filename, "r");
    if(!fp){
        fprintf(stderr, "%s can't open in %s\n", filename, __func__);
        perror("fopen");
        return NULL;
    }

    char *field;
    int state;
    size_t r = 0, c = 0;
    char ***mat = NULL;
    void *temp;

    while(field = getCSVField(fp, ',', &state)){
        if(c == 0){
            mat = realloc(mat, (r + 1)*sizeof(*mat));
            if(!mat){
                fprintf(stderr, "realloc failed in %s\n", __func__);
                exit(EXIT_FAILURE);
            }
            mat[r] = NULL;
        }
        mat[r] = realloc(mat[r], (c + 1)*sizeof(**mat));
        if(!mat[r]){
            fprintf(stderr, "realloc failed in %s\n", __func__);
            exit(EXIT_FAILURE);
        }
        mat[r][c++] = field;
        if(state == '\n' || state == EOF){
            if(*cols == 0){
                *cols = c;
            } else if(c != *cols){
                fprintf(stderr, "line %zu doesn't match number of columns in %s\n", r, filename);
                exit(EXIT_FAILURE);
            }
            c  = 0;
            *rows = ++r;
        }
    }
    fclose(fp);

    return mat;
}

#include <ctype.h>

char *trim(char *s){
    if(!s || !*s)
        return s;

    char *from, *to;

    for(from = s; *from && isspace((unsigned char)*from); ++from);
    for(to = s; *from;){
        *to++ = *from++;
    }
    *to = 0;
    while(s != to && isspace((unsigned char)to[-1])){
        *--to = 0;
    }
    return s;
}

int main(void){
    size_t rows, cols;
    char ***mat = read_csv("simp.csv", &rows, &cols);
    for(size_t r = 0; r < rows; ++r){
        for(size_t c = 0; c < cols; ++c){
            if(c)
                putchar(',');
            printf("%s", trim(mat[r][c]));
            free(mat[r][c]);
        }
        puts("");
        free(mat[r]);
    }
    free(mat);
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

c ++ / cli ref类和使用句柄的动态分配?

来自分类Dev

C 指针和动态分配

来自分类Dev

在c中动态分配内存时,是否应该同时使用if和else条件?

来自分类Dev

在C ++ 11中使用std :: sort和lambda函数对动态分配的多维C数组进行排序

来自分类Dev

在C ++ 11中使用std :: sort和lambda函数对动态分配的多维C数组进行排序

来自分类Dev

*** glibc检测到***和动态分配问题-C ++

来自分类Dev

shell C 中的动态分配和分段错误

来自分类Dev

如何使用任意`&mut`引用成员和动态分配?

来自分类Dev

动态分配和线程

来自分类Dev

特征和动态分配

来自分类Dev

动态分配和指针

来自分类Dev

c ++动态分配初始值

来自分类Dev

C字符串和(整数,双精度数,浮点数)之间的动态分配

来自分类Dev

函数和返回指针中2D数组的C动态分配

来自分类Dev

是否可以在C中返回和释放动态分配的数组?

来自分类Dev

如何将double的动态分配结构和子结构的内容传输到数组?(C)

来自分类Dev

简化C函数中的宏(动态分配的数组和MPI_Recv)

来自分类Dev

C中的全局变量和动态分配的v变量有什么区别?

来自分类Dev

使用动态分配的数组和realloc()实现一些常见的ADT

来自分类Dev

为什么使用malloc segfault进行char **和char *类型的动态分配?

来自分类Dev

使用动态分配的数组和realloc()实现一些常见的ADT

来自分类Dev

如何仅使用 html 和 css 动态分配背景图像 url?

来自分类Dev

使用C从数组中读取和存储csv文件中的值

来自分类Dev

静态和动态分配内存

来自分类Dev

动态分配和复制数组

来自分类Dev

C ++强制使用unique_ptr动态分配?

来自分类Dev

使用指向结构C ++的指针创建动态分配的数组

来自分类Dev

C ++强制使用unique_ptr动态分配?

来自分类Dev

使用malloc在C中动态分配内存

Related 相关文章

  1. 1

    c ++ / cli ref类和使用句柄的动态分配?

  2. 2

    C 指针和动态分配

  3. 3

    在c中动态分配内存时,是否应该同时使用if和else条件?

  4. 4

    在C ++ 11中使用std :: sort和lambda函数对动态分配的多维C数组进行排序

  5. 5

    在C ++ 11中使用std :: sort和lambda函数对动态分配的多维C数组进行排序

  6. 6

    *** glibc检测到***和动态分配问题-C ++

  7. 7

    shell C 中的动态分配和分段错误

  8. 8

    如何使用任意`&mut`引用成员和动态分配?

  9. 9

    动态分配和线程

  10. 10

    特征和动态分配

  11. 11

    动态分配和指针

  12. 12

    c ++动态分配初始值

  13. 13

    C字符串和(整数,双精度数,浮点数)之间的动态分配

  14. 14

    函数和返回指针中2D数组的C动态分配

  15. 15

    是否可以在C中返回和释放动态分配的数组?

  16. 16

    如何将double的动态分配结构和子结构的内容传输到数组?(C)

  17. 17

    简化C函数中的宏(动态分配的数组和MPI_Recv)

  18. 18

    C中的全局变量和动态分配的v变量有什么区别?

  19. 19

    使用动态分配的数组和realloc()实现一些常见的ADT

  20. 20

    为什么使用malloc segfault进行char **和char *类型的动态分配?

  21. 21

    使用动态分配的数组和realloc()实现一些常见的ADT

  22. 22

    如何仅使用 html 和 css 动态分配背景图像 url?

  23. 23

    使用C从数组中读取和存储csv文件中的值

  24. 24

    静态和动态分配内存

  25. 25

    动态分配和复制数组

  26. 26

    C ++强制使用unique_ptr动态分配?

  27. 27

    使用指向结构C ++的指针创建动态分配的数组

  28. 28

    C ++强制使用unique_ptr动态分配?

  29. 29

    使用malloc在C中动态分配内存

热门标签

归档