将数据分配给2D阵列并显示它

时间:2017-03-18 11:17:46

标签: c arrays csv 3d memcpy

我正在编写一个程序,它将打开csv文件并将数据保存到3D数组中。 大多数代码工作得很好,但是我将记录分配给2D数组时遇到了问题。

这是一段代码:

#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++;
   }

1 个答案:

答案 0 :(得分:1)

使用fgets读取文件的每一行。 strpbrk可用于查找分隔符。两个指针可用于获取分隔符之间的字符数。然后分配内存并使用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;
}