使用C将字符串的csv文件读取到2D char *数组

时间:2015-02-11 11:24:36

标签: c arrays pointers csv

我搜索并搜索了一个解决方案,可以找到关于int,float,double的多维数组的大量答案,但没有char *。我想我已经掌握了指针的原理,知道char,char *和char []等之间的区别,但指向二维char指针数组的指针对我来说更好。我试图解析csv文件并用字符串填充我的2D数组(char *)。这是我的代码:

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

#define COLS 10
#define ROWS 1000

int main (void) {
        char***myarray;
        FILE *fp;
        char charTemp[100];
        char *varTemp = NULL;
        char *strTemp = NULL;
        int i, j;

        // allocate memory to hold array ROWS
        if (( myarray = (char***) malloc(ROWS * sizeof(char**))) == NULL )
            return -1;

        // then allocate memory to hold array COLS
        for (i = 0; i < ROWS; i++)
        {
            if (( myarray[i] = (char**) malloc(COLS * sizeof(char**))) == NULL )
                return -2;
        }

        // read file
        if ((fp = fopen ("myfile.csv", "r")) == NULL)
            return -3;

        // parse and fill 'myarray'
        i = 0;
        j = 0;

        while (!feof(fp) && fgets(charTemp, sizeof charTemp, fp)) {
                strTemp = strtok(charTemp, ",");
                while (strTemp != NULL) {
                    sscanf(strTemp, "%s", &varTemp);
                    myarray[i][j] = varTemp;
                    printf("%s ", myarray[i][j]);
                    j++;
                    if (j > COLS - 1)
                        j = 0;
                    strTemp = strtok( NULL, "," );
                }   
                printf("\n");
                i++;
            }
        return 0;
}

myfile.csv看起来像这样:

ABCD,1,0.2,0.5,0,A123,ZZ,1,120,1
BCDE,1.038,0,0.525,0,B321,YY,1.25,100,0.7
CDEF,1,0.2,0.5,0,C3P0,XX,1,120,1
DEFG,,,,,,,,,
EFGH,1,0.3,0.8,0,R2D2,WW,1.25,120,1
FGHI,,,,,,,,,
etc.....

我知道有些是整数和浮动等但是我希望它们都以char *的形式进入,然后我可以在atoi或其他什么时候需要使用它们。

printf只是为了查看我加载到测试的内容。如果我使用令牌%。* s显示,如果我使用%s它在printf行的段错误。我认为这意味着我在字符串末尾缺少空指针??

调试表明varTemp正在使用超出范围的内存。此外,当在第一个键之后没有数据的行上使用带有%.*s的printf时,它会在COL 1位置打印COL 0,同时应该有一个NULL指针。即:

ABCD 1 0.2 0.5 0 A123 ZZ 1 120 1
BCDE 1.038 0 0.525 0 B321 YY 1.25 100 0.7
CDEF 1 0.2 0.5 0 C3P0 XX 1 120 1
DEFG DEFG
EFGH 1 0.3 0.8 0 R2D2 WW 1.25 120 1
FGHI FGHI
etc.....

我很困惑,有什么想法吗?!

1 个答案:

答案 0 :(得分:2)

你永远不会为varTemp分配空间,你需要空间来存储scanf() d字符串,所以你可以试试这个

char varTemp[100];
以这种方式

scanf()

sscanf(strTemp, "%99s", varTemp);

然后通过varTemp然后malloc()strcpy()字符串复制到数组中。

您需要复制字符串的原因是因为您将在后续调用sscanf()时覆盖它,因此您将其复制并使用varTemp作为缓冲区来存储scanf() ed字符串

另外Don't cast malloc()以及!feof(fp)循环中的while检查是多余的,它永远不会成立,因为当您到达文件末尾时fgets()将返回NULL之后,feof()将为真,所以它永远不会被评估何时返回true。

在这种情况下,因为sizeof(char *) == sizeof(char **)并不重要,但通常情况下,malloc()的明星数量应少于malloc()指针的明星数量,因此< / p>

if ((myarray[i] = malloc(COLS * sizeof(char *))) == NULL)

会更容易理解,并且在失败时你只需从main()返回而不释放先前分配的指针。

最后,如果COLSROWS是固定值,则绝对不需要malloc(),除非您的数组稍后会调整大小,或者它们太大而无法容纳它们。< / p>

char *varTemp是一个指针,因为它应该指向某个地方有效,你可以通过malloc()从操作系统请求某些内容,使其指向某处,如

char *varTemp;
varTemp = malloc(NumberOfBytesIWant);
if (varTemp == NULL)
    ohNo_TheSystemDidNotGiveMeMemory_PerhapsThereIsNoMemoryLeft_IShouldNotContinue();
/* now varTemp is accessible and you are allowed to write NumberOfBytesIWant
 * into it. But you must remember to calll 'free(varTemp)' later when you no
 * longer need the data.
 */

我不是唯一可以让它指向某个地方的方法,这样你就可以动态分配空间,这通常是你找到需要多少字节的合适解决方案,然后只是要求这个数量,没有更多,也没有更少,但这也可以工作

char array[100];
char *varTemp;

varTemp = array;

c中的数组衰减为指针,因此上述内容有效,在此示例中varTemp也可以访问,例如sscanf(sourceString, "%99s", varTemp);

但是当你没有用指针指向任何有效的内存地址时,尝试访问它是未定义的行为,因为指针所指向的未定义