你问:
关于在 malloced 字符串上使用 strtok 有什么我应该知道的吗?
有很多事情需要注意。首先,strtok()
在处理字符串时修改字符串,'\0'
在找到分隔符的地方插入空值 ( )。这不是分配内存的问题(这是可修改的!);如果您尝试将常量字符串传递给strtok()
.
free()
其次,你必须有尽可能多的调用malloc()
和calloc()
(但realloc()
可能会打乱计数)。
在我的代码中,我有(一般而言)
char* line=getline();
Parse(dest,line);
free(line);
除非Parse()
分配它保留的空间,否则dest
在dest
调用free()
. free()
释放分配的空间以及getline()
之后对指针的任何使用都会产生未定义的行为。请注意,未定义的行为包括“看似有效,但只是巧合”的选项。
其中 getline() 是一个将 char * 返回到某个 malloced 内存的函数,而 Parse(dest, line) 是一个在线解析的函数,将结果存储在 dest 中(之前已部分填充,来自其他信息)。
Parse() 在线调用 strtok() a 的次数不定,并进行一些验证。每个令牌(指向 strtok() 返回的指针)都被放入队列中,直到我知道我有多少。
请注意,返回的指针strtok()
都是指向由 分配的单个空间块的指针getline()
。您没有描述任何额外的内存分配。
然后将它们复制到 dest 中的 malloc'd char** 上。
这听起来好像您将指针从strtok()
指针数组中复制出来,但您并没有注意复制这些指针指向的数据。
现在 free(line) 和一个释放 dest 中 char*[] 的每个部分的函数,两者都出现在 valgrind 上:
"Address 0x5179450 is 8 bytes inside a block of size 38 free'd"
或类似的东西。
free()
' char *[]
' 部分的第一个dest
可能有一个指向line
并因此释放整个内存块的指针。部分的所有后续释放dest
都试图释放未返回的地址malloc()
,并valgrind
试图告诉你这一点。然后free(line)
操作失败,因为第一个free()
指针dest
已经释放了该空间。
我正在考虑重构我的代码 [以] 存储它们的副本 [...]。
提议的重构可能是明智的;其他人已经提到的功能strdup()
将整齐可靠地完成工作。
请注意,重构之后,您仍然需要释放行,但不会释放任何返回的指针strtok()
。它们只是指向由(标识)管理的空间的指针,line
并且将在您释放时全部释放line
。
请注意,您需要释放每个单独分配的 ( strdup()
'd) 字符串以及通过dest
.
或者,不要在呼叫后立即释放线路Parse()
。记录dest
分配的指针 ( line
) 并在释放指针数组时释放它。但是,您仍然没有释放由 返回的指针strtok()
。