使用 strtok_r 时指针无效
invalid pointer when using strtok_r
当 运行 我的代码(显示在第一个代码块中)时,出现此错误:
*** Error in `./a.out': free(): invalid pointer: 0x0000000001e4c016 ***
我找到了一个修复程序(显示在第二个代码块中),但我不明白为什么会首先发生错误。
我阅读了有关 strtok_r 的文档,但我不明白为什么将“str”分配给新的 char* 可以解决问题。
“rest = str”不是说rest和str指向同一个内存块吗?这如何解决问题???
损坏的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* str = (char*) malloc(sizeof(char) * 128);
char* token;
printf("Enter something: ");
fgets(str, 128, stdin);
while ((token = strtok_r(str, " ", &str))) {
printf("%s\n", token);
}
free(str);
return (0);
}
固定码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* str = (char*) malloc(sizeof(char) * 128);
char* token;
char* rest = str;
printf("Enter something: ");
fgets(str, 128, stdin);
while ((token = strtok_r(rest, " ", &rest))) {
printf("%s\n", token);
}
free(str);
return (0);
}
很明显,strtok_r
的调用更改了作为第三个参数通过引用传递给调用的指针 str
。
while ((token = strtok_r(str, " ", &str))) {
^^^^
printf("%s\n", token);
}
所以在函数调用后指针str
可以指向原始字符串内部。因此它不会存储调用 malloc
.
后的值
因此使用辅助变量rest可以让指针保持初始值str
.
注意你调用的函数有误。这是它的描述
On the first call to strtok_r()
, str
should point to the string to be
parsed, and the value of saveptr
is ignored. In subsequent calls, str
should be NULL
, and saveptr
should be unchanged since the previous
call.
因此对于函数的第二次和后续调用,第一个参数应为 NULL
。
你应该写:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char str[128];
char *token;
char *rest = str;
printf("Enter something: ");
fgets(str, sizeof str, stdin);
for (token = strtok_r(rest, " ", &rest);
token = strtok_r(NULL, " ", &rest);
/* just nothing here */)
{
printf("%s\n", token);
}
return (0);
}
- 首先,您不需要为
str
分配内存,因为您可以定义一个本地数组来存储数据。您可以使用 sizeof
运算符,这样如果您决定更改 str
的大小,就不会 运行 在两个地方不更新它的风险。在使用 malloc
的情况下,你最好 #define
一个常量来保存值,而你在使用分配缓冲区大小的任何地方都使用常量。
- 其次,从不 转换
malloc
的 returned 值。相信我,这是一个非常糟糕的习惯。当你进行强制转换时,你告诉编译器你知道你在做什么。转换 malloc
的值是 C 中没有 void
类型时的遗留问题(这是八十年代中期的事)。曾几何时,malloc()
用于 return 一个通常不是您想要的指针类型的 char *
,您必须转换指针以匹配您正在使用的指针。不仅不建议在 2021 年转换 malloc()
return 值,而且强烈建议不要这样做,因为转换它会导致许多错误(编译器会在您做错事情时警告您,但它不会,如果你转换值,通常这会被解释为你告诉编译器你故意做一些奇怪的事情,所以编译器闭嘴,不再多说)
- 第三,如果要提取一个字符串中的所有token,第一次需要调用
strtok()
(或者他的朋友strtok_w
),第一个参数指向start字符串的 但其余调用必须使用 NULL
作为第一个参数 完成,否则您将在字符串中搜索 returned,而不是在第一次出现之后。您的问题不在于使用 strtok
或 strtok_r
,因为 strtok_r
只是 strtok
的可重入版本,它允许您在第一个内部开始嵌套循环,或者从不同的线程调用它。
堆内存管理跟踪用于实现库调用的基本内存地址。我们需要在必要时将这些基地址保存到 free/reallocate。
既然您找到了使用 strtok_r()
的方法,我更喜欢以下版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char orgStr [] = "strtok does not allow you to have 2 pointers going at once on the same string";
for (char *token, *rmdStr = orgStr; token = strtok_r (NULL, " ", &rmdStr); /* empty */) {
printf ("%s\n", token);
}
/* Original string is chopped up with NULCHAR, now unreliable */
}
当 运行 我的代码(显示在第一个代码块中)时,出现此错误:
*** Error in `./a.out': free(): invalid pointer: 0x0000000001e4c016 ***
我找到了一个修复程序(显示在第二个代码块中),但我不明白为什么会首先发生错误。
我阅读了有关 strtok_r 的文档,但我不明白为什么将“str”分配给新的 char* 可以解决问题。
“rest = str”不是说rest和str指向同一个内存块吗?这如何解决问题???
损坏的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* str = (char*) malloc(sizeof(char) * 128);
char* token;
printf("Enter something: ");
fgets(str, 128, stdin);
while ((token = strtok_r(str, " ", &str))) {
printf("%s\n", token);
}
free(str);
return (0);
}
固定码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* str = (char*) malloc(sizeof(char) * 128);
char* token;
char* rest = str;
printf("Enter something: ");
fgets(str, 128, stdin);
while ((token = strtok_r(rest, " ", &rest))) {
printf("%s\n", token);
}
free(str);
return (0);
}
很明显,strtok_r
的调用更改了作为第三个参数通过引用传递给调用的指针 str
。
while ((token = strtok_r(str, " ", &str))) {
^^^^
printf("%s\n", token);
}
所以在函数调用后指针str
可以指向原始字符串内部。因此它不会存储调用 malloc
.
因此使用辅助变量rest可以让指针保持初始值str
.
注意你调用的函数有误。这是它的描述
On the first call to
strtok_r()
,str
should point to the string to be parsed, and the value ofsaveptr
is ignored. In subsequent calls,str
should beNULL
, andsaveptr
should be unchanged since the previous call.
因此对于函数的第二次和后续调用,第一个参数应为 NULL
。
你应该写:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char str[128];
char *token;
char *rest = str;
printf("Enter something: ");
fgets(str, sizeof str, stdin);
for (token = strtok_r(rest, " ", &rest);
token = strtok_r(NULL, " ", &rest);
/* just nothing here */)
{
printf("%s\n", token);
}
return (0);
}
- 首先,您不需要为
str
分配内存,因为您可以定义一个本地数组来存储数据。您可以使用sizeof
运算符,这样如果您决定更改str
的大小,就不会 运行 在两个地方不更新它的风险。在使用malloc
的情况下,你最好#define
一个常量来保存值,而你在使用分配缓冲区大小的任何地方都使用常量。 - 其次,从不 转换
malloc
的 returned 值。相信我,这是一个非常糟糕的习惯。当你进行强制转换时,你告诉编译器你知道你在做什么。转换malloc
的值是 C 中没有void
类型时的遗留问题(这是八十年代中期的事)。曾几何时,malloc()
用于 return 一个通常不是您想要的指针类型的char *
,您必须转换指针以匹配您正在使用的指针。不仅不建议在 2021 年转换malloc()
return 值,而且强烈建议不要这样做,因为转换它会导致许多错误(编译器会在您做错事情时警告您,但它不会,如果你转换值,通常这会被解释为你告诉编译器你故意做一些奇怪的事情,所以编译器闭嘴,不再多说) - 第三,如果要提取一个字符串中的所有token,第一次需要调用
strtok()
(或者他的朋友strtok_w
),第一个参数指向start字符串的 但其余调用必须使用NULL
作为第一个参数 完成,否则您将在字符串中搜索 returned,而不是在第一次出现之后。您的问题不在于使用strtok
或strtok_r
,因为strtok_r
只是strtok
的可重入版本,它允许您在第一个内部开始嵌套循环,或者从不同的线程调用它。
堆内存管理跟踪用于实现库调用的基本内存地址。我们需要在必要时将这些基地址保存到 free/reallocate。
既然您找到了使用 strtok_r()
的方法,我更喜欢以下版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char orgStr [] = "strtok does not allow you to have 2 pointers going at once on the same string";
for (char *token, *rmdStr = orgStr; token = strtok_r (NULL, " ", &rmdStr); /* empty */) {
printf ("%s\n", token);
}
/* Original string is chopped up with NULCHAR, now unreliable */
}