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

标签 c arrays pointers csv

我已经搜索并搜索了这个问题的解决方案,可以找到很多关于 int、float、double 多维数组的答案,但没有 char*。我想我已经掌握了指针的原理,知道 char、char* 和 char[] 等之间的区别,但指向 char 指针的二维数组的指针已经打败了我。我正在尝试解析 csv 文件并用字符串(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.....

我知道有些是整数和 float 等,但我希望它们全部作为 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.....

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

最佳答案

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

char varTemp[100];

scanf()这样

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

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

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

还有Don't cast malloc() ,而 while 循环中的这个 !feof(fp) 检查是多余的,它永远不会是真的,因为当你到达文件末尾时 fgets() 将返回 NULL,然后 feof() 将为 true,因此当它返回 true 时永远不会对其进行求值。

在这种情况下并不重要,因为 sizeof(char *) == sizeof(char **) 但作为规则,您应该 malloc() 与比您要 malloc() 的指针少一颗星,因此

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

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

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

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); .

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

关于c - 使用 C 将字符串的 csv 文件读取到 2D char* 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28453125/

相关文章:

c++ - 如何将我的项目转换为多线程应用程序

c++ - 在链接时合并全局数组/从多个编译单元填充全局数组

python - pandas 数据帧上 numpy.where 方法的结果是在完整数组还是过滤后的数组上计算的?

c - 数组到 C 中的链表函数;如何遍历列表以附加节点?

c++ - 在列表中向下移动一个元素 C++

c++ - 指针和变量

c - 如何在运行时确定共享库中全局变量的地址范围?

c - 如何识别接入点中 UDP 数据包的来源?

javascript - 将值赋给数组内的数组

c# - 接口(interface)不通过引用传递