6

这 2 个错误与链表/低级文件读取/strtok 程序有关。

==10982== Use of uninitialised value of size 4
==10982==    at 0x40C3899: strtok (strtok.S:197)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)
==10982== 
==10982== Use of uninitialised value of size 4
==10982==    at 0x40C38C1: strtok (strtok.S:223)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)
==10982== 
==10982== Conditional jump or move depends on uninitialised value(s)
==10982==    at 0x40C38C4: strtok (strtok.S:224)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)

这是函数 buildList

void buildList(int fdin, int lines)
{
    char ara[4096];
    int num;
    double p;
    read(fdin, ara, 4096);
    char *nl = "\n";
    char *ws = " ";
    char *temp =  strtok(ara, " ");
    while(temp != NULL)
    {
        Stock *s = (Stock*)calloc(1, sizeof(Stock));
        s->c.symbol = (char*)calloc(strlen(temp)+1, sizeof(char));
        strcpy(s->c.symbol, temp);
        temp = strtok(NULL, "\n");
        s->c.name = (char*)calloc(strlen(temp)+1, sizeof(char));
        strcpy(s->c.name, temp);
        temp = strtok(NULL, "\n");
        sscanf(temp, "%lf", &p);
        temp = strtok(NULL, "\n");
        s->price = p;
        sscanf(temp, "%d", &num);
        s->shares = num;
        Node *n = (Node*)calloc(1, sizeof(Node));
        n->data = s;
        addOrdered(n);
        temp = strtok(NULL, " ");
    }
    close(fdin);
}

我无法弄清楚为什么会发生此错误。从我读过的内容来看,这是因为我将事物分配给 strtok 中的 char* 而没有为它们分配任何内存。然而,这就是我过去的做法,我认为这很好。

4

3 回答 3

6

正如其他人所猜测的那样,valgrind正在抱怨strtok正在使用未初始化的内存。然后问题转向为什么,因为它似乎是通过以下方式初始化的:

read(fdin, ara, 4096);

但是,read()不会\0终止数据,而strtok需要一个\0终止的字符串。确保输入正确终止:

ssize_t result = read(fdin, ara, sizeof(ara)-1); /* leave room for '\0' */
ara[result > 0 ? result : 0] = '\0';

Lee Daniel Crocker的memset(ara, 0, sizeof(ara));建议相当于相同类型的修复,但它仅在文件包含少于sizeof(ara)字节的输入时才有效。如果您从中读取的文件具有 4096 字节或更多的数据,您仍然会遇到类似的问题。然后,strtok将被迫扫描缓冲区的末尾以查找\0,从而导致未定义的行为。

于 2013-05-24T23:36:37.630 回答
3

read(fdin, ara, 4096);

...可能会返回:

  • -1,表示读取出错,ara未填写;
  • 0,表示你到达了文件的末尾,并且ara没有被填写;
  • a value < 4096,表示文件中剩余的字节数少于 4096,并且并非所有字节ara都被填充。

始终检查read().

char *temp = strtok(ara, " ");

$ man strtok

...

The strtok() function is used to isolate sequential tokens in a null-ter-
minated string, str. ...

没有任何东西可以保证其中ara包含空字符 ( '\0'),因此您无法有效地将其交给strtok(). 如果您想确保其中有一个,请在阅读后制作char ara[4097]并执行。ara[4096] = '\0';'\0'

或者,更好的是,如果read()的返回值在变量data_read中,并且您已经检查以确保它不是 -1,请执行ara[data_read] = '\0';,以便将最后一个读取后的字节设置为'\0'.

如果文件有超过 4096 个字符,并且您的read()调用读取了例如几行和另一行的开头,会发生什么情况?鉴于此,您可能需要考虑使用fopen()来打开文件并使用fgets()来读取行。

于 2013-05-24T23:39:30.930 回答
1

读取的数据read末尾是否有空终止符?如果不是,那可能就是问题所在。

于 2013-05-24T23:35:55.530 回答