C 标记化字符串循环内存错误
我在一个数组中循环,试图获取每个令牌并插入到另一个字符串数组(char**),我从valgrind得到了无效的写操作以及未初始化值的使用。我该如何解决这个问题C 标记化字符串循环内存错误,c,memory,token,tokenize,C,Memory,Token,Tokenize,我在一个数组中循环,试图获取每个令牌并插入到另一个字符串数组(char**),我从valgrind得到了无效的写操作以及未初始化值的使用。我该如何解决这个问题 char *tstring; int i = 0; char **tokens = (char **)malloc(sizeof(contents)); tstring = strtok(contents, "\"(),-> "); printf("si
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++;
}
注意,我在开始时分配了**令牌,而不是像netcoder那样将其保留为空,因为这也给了我一个问题
这里是瓦尔格兰德:
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)对于初学者,您可以:
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]
最后,始终检查malloc
和realloc
的返回值。对于初学者,您需要:
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]
最后,始终检查
malloc
和realloc
的返回值。当您使用malloc时,您传递的是sizeof(ptr)
,因此它为64位指针分配了8个字节。您希望malloc(strlen(ptr)+1)
并以null终止它
将
sizeof(tstring)
打印到终端,这应该会验证它。当您malloc时,您传递的是sizeof(ptr)
,因此它为64位指针分配了8个字节。您希望malloc(strlen(ptr)+1)
并以null终止它
将
sizeof(tstring)
打印到终端,这将验证它。sizeof
提供变量的大小,而不是字符串的长度。请尝试strlen
。char**tokens=(char**)malloc(sizof*tokens*sizeof(contents))代码>顺便问一下:什么是内容?指针还是数组?或typedef类型?请不要强制转换malloc的返回值。sizeof
提供变量的大小,而不是字符串的长度。请尝试strlen
。char**tokens=(char**)malloc(sizof*tokens*sizeof(contents))代码>顺便问一下:什么是内容?指针还是数组?还是typedef类型?请不要强制转换malloc的返回值。您忘记了i+1(在i+1*sizeof(char*)
中)周围的括号。非常感谢。是代币[i]=对于循环的条件是否为NULL可行?@PeteJodo,strtok
在找不到更多令牌时返回NULL。您必须先检查返回值,然后再尝试复制它(或对其调用strlen
),并将其用作循环条件。您忘记了i+1(在i+1*sizeof(char*)
中)周围的括号。非常感谢。是代币[i]=对于循环的条件是否为NULL可行?@PeteJodo,strtok
在找不到更多令牌时返回NULL。您必须先检查返回值,然后再尝试复制它(或对其调用strlen
),并将其用作循环条件。