【问题标题】:Tokenizing string loop memory errors标记字符串循环内存错误
【发布时间】:2012-11-21 21:19:56
【问题描述】:

我正在遍历一个数组,试图获取每个标记并插入另一个字符串数组 (char**),但我收到了来自 valgrind 的无效写入以及未初始化值的使用。我将如何解决这个问题?

        char *tstring;
        int i = 0;
        char **tokens = (char **)malloc(sizeof(contents));
        tstring = strtok(contents, "\"(),-> ");
        printf("sizeof(tstring) = %ld\tsizeof(*tstring) = %ld\nsizeof(contents) = %ld\n", sizeof(tstring), sizeof(*tstring), sizeof(contents));
        tokens[i] = (char*)malloc(sizeof(tstring));
        printf("tstring address: %p\ntokens address: %p\ntokens[i] address: %p\n",tstring,tokens, tokens[i]);
        strcpy(tokens[i], tstring);
        printf("token[0]: %s\n", tokens[i]);
        while( tokens[i] != NULL ) {
                i++;
                tstring = strtok(NULL, "\"(),-> ");
                if(tstring != NULL)
                        printf("token[%d]: %s\n", i, tstring);
                tokens[i] = (char*)malloc(sizeof(tstring));
                strcpy(tokens[i], tstring);
        }

这是被标记的字符串

"a" -> ("boo", 1), ("baa", 1)
"baa" -> ("baa", 1)
"boo" -> ("boo", 1)
"cat" -> ("baa", 1)
"dog" -> ("boo", 1)
"name" -> ("boo", 2), ("baa", 1)

这是 valgrind 的输出

sizeof(tstring) = 8 sizeof(*tstring) = 1
sizeof(contents) = 8
tstring address: 0x51f1041
tokens address: 0x51f1490
tokens[i] address: 0x51f14e0
token[0]: a
token[1]: boo
==4101== Invalid write of size 8
==4101==    at 0x400F3B: Create_List_Container (search.c:166)
==4101==    by 0x4012D5: main (search.c:234)
==4101==  Address 0x51f1498 is 0 bytes after a block of size 8 alloc'd
==4101==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4101==    by 0x400E1A: Create_List_Container (search.c:154)
==4101==    by 0x4012D5: main (search.c:234)
==4101== 
==4101== Invalid read of size 8
==4101==    at 0x400F4F: Create_List_Container (search.c:167)
==4101==    by 0x4012D5: main (search.c:234)
==4101==  Address 0x51f1498 is 0 bytes after a block of size 8 alloc'd
==4101==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4101==    by 0x400E1A: Create_List_Container (search.c:154)
==4101==    by 0x4012D5: main (search.c:234)
==4101== 
==4101== Invalid read of size 8
==4101==    at 0x400F6A: Create_List_Container (search.c:161)
==4101==    by 0x4012D5: main (search.c:234)
==4101==  Address 0x51f1498 is 0 bytes after a block of size 8 alloc'd
==4101==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4101==    by 0x400E1A: Create_List_Container (search.c:154)
==4101==    by 0x4012D5: main (search.c:234)
==4101== 
token[2]: 1
token[3]: baa
token[4]: 1
token[5]: 

token[6]: baa
token[7]: baa
token[8]: 1
token[9]: 

token[10]: boo
token[11]: boo
token[12]: 1
token[13]: 

token[14]: cat
token[15]: baa
token[16]: 1
token[17]: 

token[18]: dog
token[19]: boo
token[20]: 1
token[21]: 

token[22]: name
token[23]: boo
token[24]: 2
token[25]: baa
token[26]: 1
==4101== Use of uninitialised value of size 8
==4101==    at 0x4EBD146: strtok (strtok.S:172)
==4101==    by 0x400EFA: Create_List_Container (search.c:163)
==4101==    by 0x4012D5: main (search.c:234)
==4101== 
==4101== Conditional jump or move depends on uninitialised value(s)
==4101==    at 0x4EBD149: strtok (strtok.S:173)
==4101==    by 0x400EFA: Create_List_Container (search.c:163)
==4101==    by 0x4012D5: main (search.c:234)
==4101== 
token[27]: 

编辑:仍然出现错误

所以我修改了 netcoder 给我的代码,但仍然在令牌 [i] 被 malloc'd 的地方发生无效的写入和读取

代码如下:

    char **tokens = malloc(sizeof(char*)+1);
    if (tokens == NULL) {
            // handle malloc error
            printf("Unable to allocate memory. Exiting...\n");
            exit(0);
    }

    // ...
    while (1) {
            if(i == 0) tstring = strtok(contents, "\"(),-> ");
            else tstring = strtok(NULL, "\"(),-> ");

            if(tstring == NULL) break;

            printf("tstring: %s\tlen(tstring): %d\n", tstring, strlen(tstring));

            tokens[i] = malloc(strlen(tstring)+1);
            if (tokens[i] == NULL) {
                    // handle malloc error
                    printf("Unable to allocate memory. Exiting...\n");
                    exit(0);
            }
            printf("tokens address: %p\t*tokens address: %p\n", tokens, tokens[i]);

            char** tmp = realloc(tokens, (i+2)*sizeof(char*));
            if (tmp == NULL) { 
                    // handle realloc error
                    printf("Unable to reallocate memory. Exiting...\n");
                    exit(0);
            }       
            tokens = tmp;

            strcpy(tokens[i], tstring);
            printf("tokens[%d]: %s\n", i, tokens[i]);
            i++;
    }

请注意,我在开始时分配了 **tokens,而不是像 netcoder 那样将其保留为 NULL,因为这也给了我一个问题。

这是 valgrind:

tstring: a  len(tstring): 1
tokens address: 0x51f1490   *tokens address: 0x51f14e0
tokens[0]: a
tstring: boo    len(tstring): 3
==4609== Invalid write of size 8
==4609==    at 0x400F3E: Create_List_Container (search.c:185)
==4609==    by 0x401388: main (search.c:270)
==4609==  Address 0x51f1538 is 0 bytes after a block of size 8 alloc'd
==4609==    at 0x4C2B7B2: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4609==    by 0x400FB1: Create_List_Container (search.c:193)
==4609==    by 0x401388: main (search.c:270)
==4609== 
==4609== Invalid read of size 8
==4609==    at 0x400F4E: Create_List_Container (search.c:186)
==4609==    by 0x401388: main (search.c:270)
==4609==  Address 0x51f1538 is 0 bytes after a block of size 8 alloc'd
==4609==    at 0x4C2B7B2: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4609==    by 0x400FB1: Create_List_Container (search.c:193)
==4609==    by 0x401388: main (search.c:270)
==4609== 
==4609== Invalid read of size 8
==4609==    at 0x400F77: Create_List_Container (search.c:191)
==4609==    by 0x401388: main (search.c:270)
==4609==  Address 0x51f1538 is 0 bytes after a block of size 8 alloc'd
==4609==    at 0x4C2B7B2: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4609==    by 0x400FB1: Create_List_Container (search.c:193)
==4609==    by 0x401388: main (search.c:270)
==4609== 
tokens address: 0x51f1530   *tokens address: 0x51f1580
==4609== Use of uninitialised value of size 8
==4609==    at 0x4C2BFFC: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4609==    by 0x400FF7: Create_List_Container (search.c:201)
==4609==    by 0x401388: main (search.c:270)
==4609== 
==4609== Invalid write of size 1
==4609==    at 0x4C2BFFC: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4609==    by 0x400FF7: Create_List_Container (search.c:201)
==4609==    by 0x401388: main (search.c:270)
==4609==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

固定,realloc中应该是(i+2)

【问题讨论】:

  • sizeof 为您提供变量的大小,而不是字符串的长度。试试strlen
  • char **tokens = (char **)malloc(sizof *tokens * sizeof(contents)); BTW:什么是内容?指针还是数组?还是 typedef 类型?
  • 请不要强制转换malloc的返回值。

标签: c memory token tokenize


【解决方案1】:

对于初学者,您可以这样做:

tokens[i] = (char*)malloc(sizeof(tstring));

首先,不要转换malloc的返回值。其次,您可能正在寻找strlen,而不是sizeof

tokens[i] = malloc(strlen(tstring)+1); // +1 for the null terminator

...你至少犯了两次这个错误。

然后,是这样的:

char **tokens = (char **)malloc(sizeof(contents));

...再次,转换malloc 的返回值,并且sizeof(contents) 是任意的,因为您不知道要在其中存储多少元素。这是realloc 的好案例:

char **tokens = NULL;
// ...
while (...) {
    // ...
    tokens[i] = malloc(strlen(tstring)+1);
    if (tokens[i] == NULL) {
        // handle malloc error
    }

    char** tmp = realloc(tokens, (i+1)*sizeof(char*));
    if (tmp == NULL) {
        // handle realloc error
    }
    tokens = tmp;

    strcpy(tokens[i], tstring);
    i++;
}

还请注意我是如何在循环末尾移动 i++ 以防止您在应该是 tokens[0] 时访问 tokens[1]

最后,始终检查mallocrealloc 的返回值。

【讨论】:

  • 您忘记了 i+1 周围的括号(在 i+1*sizeof(char*) 中)。
  • 非常感谢。 tokens[i]!=NULL 对于循环的条件是否可行?
  • @PeteJodo, strtok 在找不到更多令牌时返回 NULL。您必须在尝试复制之前检查返回值(或在其上调用strlen),并将其用作循环条件。
【解决方案2】:

当你 malloc 时,你传递了sizeof(ptr),所以它为一个 64 位指针分配了 8 个字节。你想malloc(strlen(ptr)+1) 并以空值终止它。

sizeof(tstring) 打印到终端,这应该会验证它。

【讨论】:

    猜你喜欢
    • 2017-10-04
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    相关资源
    最近更新 更多