2017-03-18 89 views
1

我正在編寫一個程序,它將打開csv文件並將數據保存到3D數組。 大部分的代碼工作得很好,但是我在將記錄分配給二維數組時遇到了問題。將數據分配給二維數組並顯示它C

下面是一個代碼:

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

#define FILE_MODE "r" 
/* 
Explode string with given token and assign result to list variable 
*/ 
int explode(const char *src, const char *tokens, char ***list, size_t *len) 
{ 
    if(src == NULL || list == NULL || len == NULL) { 
     return 0; 
    } 

    char *str, *copy, **_list = NULL, **tmp; 
    *list = NULL; 
    *len = 0; 

    copy = strdup(src); 
    if(copy == NULL) 
     return 1; 

    str = strtok(copy, tokens); 
    if(str == NULL) { 
     goto free_and_exit; 
    } 

    _list = realloc(NULL, sizeof *_list); 
    if(_list == NULL) { 
     goto free_and_exit; 
    } 

    _list[*len] = strdup(str); 
    if(_list[*len] == NULL) 
     goto free_and_exit; 
    (*len)++; 

    while((str = strtok(NULL, tokens))) 
    { 
     tmp = realloc(_list, (sizeof *_list) * (*len + 1)); 
     if(tmp == NULL) 
      goto free_and_exit; 

     _list = tmp; 

     _list[*len] = strdup(str); 
     if(_list[*len] == NULL) 
      goto free_and_exit; 
     (*len)++; 
    } 

free_and_exit: 
    *list = _list; 
    free(copy); 

    return 2; 
} 

/* 
Exploding lines in CSV file 
*/ 
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 NULL; 
} 


int main() 
{ 
    FILE *stream; 
    char fileName[256], table[256], line[256], 
     **list, **columns, **data; 
    size_t length; 

    printf("Witaj uzytkowniku! Podaj nazwe pliku z rozszerzeniem .csv. \n"); 
    scanf("%s", fileName); 

    explode(fileName, ".", &list, &length); 
    strcpy(table, list[0]); 

    stream = fopen("file.csv", FILE_MODE); // not to write path every single time 

    if (stream == NULL) { 
     printf("Nie moge otworzyc pliku %s do odczytu!\n", fileName); 
     exit(1); 
    } 

    fgets(line, sizeof line, stream); 
    explode(line, ";", &columns, &length); 

    int recordNumber = 0 
     ,columnNumber = 0; 

    while (fgets(line, sizeof line, stream)) 
    { 
     char* tmp = strdup(line); 
     if (getfield(tmp, recordNumber) != NULL) { 
      columnNumber++; 
     } 

     recordNumber++; 
     free(tmp); 
    } 

    fseek(stream, 0, SEEK_SET); // Go to beginning of file 
    fgets(line, 1024, stream); 

    int i = 0 // Number of records 
     ,h = 0; // number of columns 

    char **records[recordNumber][columnNumber]; 
    length = 0; 
    char *tmp[recordNumber]; 

    // Here I get number of lines and columns in csv file to make 3D array?? 
    while (fgets(line, sizeof line, stream) && i < recordNumber) 
    { 
     tmp[i] = strdup(line); 
     explode(tmp[i], ";", &data, &length); 

     for (h = 0; h < columnNumber; h++) 
     { 
     memcpy(records[i][h], data[h], sizeof(data[h])); 
     } 

     i++; 
    } 

    for (i = 0; i < recordNumber; i++) 
    { 
     for (h = 0; h < columnNumber; h++) 
     { 
     printf("%s ", records[i][h][0]); 
     } 
     printf("\n"); 
    } 

    fclose(stream); 
    return EXIT_SUCCESS; 
} 

問題開始,當我嘗試做一個循環,即數據分配給數組:

while (fgets(line, sizeof line, stream) && i < recordNumber) 
    { 
     tmp[i] = strdup(line); 
     explode(tmp[i], ";", &data, &length); 

     for (h = 0; h < columnNumber; h++) 
     { 
     memcpy(records[i][h], data[h], sizeof(data[h])); 
     } 

     i++; 
    } 

我試圖使用memcpy和strcpy,但沒有作品正確 - 我很確定。 代碼轉到這些行時,出現錯誤:分段錯誤(核心轉儲)。 我想要實現的是用csv文件中的數據填充此數組並打印它。

感謝您的幫助! :)


編輯:

爆炸的功能是不是我的。可能,我發現它在stackoverflow的某處。

時,它涉及到的代碼,變化不大,它的工作原理

char records[recordNumber][columnNumber][1024]; 
    length = 0; 
    char *tmp[recordNumber]; 

    while (fgets(line, sizeof line, stream) && i < recordNumber) 
    { 
     tmp[i] = strdup(line); 
     explode(tmp[i], ";", &data, &length); 

     for (h = 0; h < columnNumber; h++) 
     { 
     strcpy(records[i][h], data[h]); 
     } 

     i++; 
    } 
+0

請閱讀[問],特別是關於只包括一個[mcve]的位,而不是所有的代碼。 –

回答

1

讀取文件中的每一行與fgetsstrpbrk可用於查找分隔符。兩個指針可用於獲取分隔符之間的字符數。然後分配內存並使用memcpy將該字段複製到分配的內存。

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

char ***strpdlm (char *pdelim, int skip); 
char ***freedlm (char ***ppp); 

int main() 
{ 
    char ***expld = NULL; 
    int line = 0; 
    int field = 0; 

    //last argument of 1 is skip consecutive delimiters. 0 do not skip 
    expld = strpdlm (";\n", 1);// delimiters semicolon and newline 
    //print each extracted string 
    line = 0; 
    if (expld) {//not null 
     while (expld[line]) {//not null 
      field = 0; 
      printf ("\nfields for line %d\n", line); 
      while (expld[line][field]) {//not null 
       printf ("expld[%d][%d] %s\n", line, field, expld[line][field]); 
       field++; 
      } 
      line++; 
     } 
    } 
    //free memory and set NULL 
    expld = freedlm (expld); 

    return 0; 
} 

char ***freedlm (char ***ppp) { 
    size_t each = 0; 
    size_t item = 0; 

    if (ppp) { 
     while (ppp[each]) { 
      item = 0; 
      while (ppp[each][item]) { 
       free (ppp[each][item]); 
       item++; 
      } 
      free (ppp[each]); 
      each++; 
     } 
     free (ppp); 
    } 

    return NULL; 
} 

char ***strpdlm (char *pdelim, int skip) { 
    char ***xpld = NULL; 
    char ***temprecord = NULL; 
    char **tempfield = NULL; 
    char *pnt = NULL; 
    char *cur = NULL; 
    char line[1024] = ""; 
    int span = 0; 
    int len = 0; 
    int record = 0; 
    int field = 0; 
    FILE *pf = NULL; 

    if ((pf = fopen ("file.csv", "r")) == NULL) { 
     perror ("could not open \"file.csv\""); 
     return NULL; 
    } 

    if (pdelim) { 
     while (fgets (line, sizeof line, pf)) { 
      //make sure each line ends with \n 
      len = strcspn (line, "\n"); 
      if (len + 1 < sizeof line) { 
       line[len] = '\n'; 
       line[len + 1] = '\0'; 
      } 
      //allocate record + 2 pointers 
      if ((temprecord = realloc (xpld, (record + 2) * sizeof (*xpld))) == NULL) { 
       fprintf (stderr, "problem realloc records\n"); 
       fclose (pf); 
       return xpld; 
      } 
      xpld = temprecord; 
      xpld[record] = NULL; 

      field = 0; 
      cur = line;//cur points to line 
      while ((pnt = strpbrk (cur, pdelim))) { 
       if (pnt != cur || !skip) { 
        if ((tempfield = realloc (xpld[record], (field + 2) * sizeof (**xpld))) == NULL) { 
         fprintf (stderr, "problem realloc fields\n"); 
         fclose (pf); 
         return xpld; 
        } 
        xpld[record] = tempfield; 
        xpld[record][field] = NULL; 

        if (pnt) { 
         span = pnt - cur; 
        } 
        else { 
         span = strlen (cur); 
        } 

        if ((xpld[record][field] = malloc (span + 1)) == NULL) { 
         fprintf (stderr, "problem malloc\n"); 
         fclose (pf); 
         return xpld; 
        } 
        memcpy (xpld[record][field], cur, span); 
        xpld[record][field][span] = '\0'; 
        field++; 
        xpld[record][field] = NULL;//sentinel NULL 
       } 
       cur = pnt + 1;//set cur to point to next field 
      } 
      record++; 
      xpld[record] = NULL;//sentinel NULL 
     } 
    } 
    fclose (pf); 
    return xpld; 
} 
+0

非常感謝您的回覆。當然,我會嘗試你的代碼,但是,它似乎比我的先進得多 - 它不是完美的,但它是我的研究計劃:) – Franky