C:将 strtok 令牌分配给 char * Segfault



为什么下面的代码会出现段错误?

#include <stdio.h>
int main()
{
char * tmp = "0.1";
char * first = strtok(tmp, ".");
return 0;
}

编辑:

#include <stdio.h>
int main()
{
char tmp[] = "0.1";
char *first = strtok(tmp, ".");
char *second = strtok(tmp, "."); // Yes, should be NULL
printf("%sn", first);       
printf("Hello Worldn");
return 0;
}

段错误可以在在线 gdb 上复制: https://www.onlinegdb.com/online_c_compiler

第一个代码的问题在于tmp指向字符串文本,这是只读的。当strtok尝试修改字符串时,它会崩溃。


您的第二个代码的问题缺少包括:

#include <string.h>

此缺少标头表示strtok在程序中未声明。C 编译器假定所有未声明的函数都返回int。对于返回char *strtok则不正确。示例中崩溃的可能原因是代码在 64 位计算机上运行,其中指针宽 8 字节,但指针宽度仅为 4int。这会弄乱strtok的返回值,因此first是一个垃圾指针(并且printf尝试使用它时崩溃(。

您可以通过执行以下操作来自己确认这一点

char *first = strtok(tmp, ".");
printf("%p %pn", (void *)tmp, (void *)first);

tmpfirst打印的地址应该相同(如果您#include <string.h>,则相同(。


有趣的是,gcc可以警告你这些问题:

main.c: In function 'main':
main.c:6:19: warning: implicit declaration of function 'strtok' [-Wimplicit-function-declaration]
char *first = strtok(tmp, ".");
^
main.c:6:19: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
main.c:7:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
char *second = strtok(tmp, "."); // Yes, should be NULL
^

。在线GDB会向你显示这些警告,但前提是编译失败!

因此,要在onlinegdb上看到编译器警告,您必须在代码中添加一个硬错误(例如,在文件的最后一行放置一个@(。

函数strtok的行为是这样的:

  1. 接受字符串str或 NULL 以及分隔符字符串。
  2. 然后strtok函数开始处理给定的字符串str,其中它逐个字符读取字符串,直到它遇到在提供的分隔符字符中存在的字符。
  3. 如果在到达分隔符字符串之前遇到的字符数> 0,则将分隔符替换为"",并返回指向此迭代中第一个不是分隔符字符的指针。
  4. 否则,如果在到达分隔符字符串之前遇到的字符数为 == 0,则继续迭代字符串的其余部分,而不将此分隔符替换为""。

我创建了一些代码片段,可以帮助您更好地了解函数的性质,https://ideone.com/6NCcrR 和 https://ideone.com/KVI5n4(<- 从代码中摘

录代码(

现在回答您的问题,包括string.h标题和设置char tmp[] = "0.1";应该可以解决您的问题。

使用char * tmp = "0.1";tmp指向无法修改的字符串文本,strtok尝试通过将.替换为''来修改字符串。

另一种方法是使用strchr来查找点和精度字段来打印有限数量的字符。子字符串也可以复制到其他变量。

#include <stdio.h>
#include <string.h>
int main ( void) {
char * tmp = "0.1";
char * first = strchr(tmp, '.');
char * second = first + 1;
if ( first) {
printf ( "%.*sn", first - tmp, tmp);
printf ( "%sn", second);
}
printf ( "Hello Worldn");
return 0;
}

tmp不是一个字符串文字,因为很少有答案或注释指出。

char *tmp = "0.1" 这是一个字符串文字

char tmp[] = "0.1" 是一个字符数组,所有数组操作都可以对它们执行。

出现段错误是因为找不到 strtok 的函数声明,因为不包含string.h,并且默认情况下 gcc 或其他 c 编译器隐式将返回类型声明为 int

现在根据平台的不同,整数大小可能会有所不同,如果 int 大小分别为4字节,指针大小分别为8 字节

char *first = (int(strtok(tmp,"."(;

截断发生在 strtok 返回的指针地址上,然后在打印时,您正在取消引用FIRST 中包含的地址值,这可能是超出界限的内存区域,导致分段错误或未定义的行为。

如果您可以将 strtok 的输出类型转换为 8 字节的类型(在我的情况下很长(,那么就不会有段错误,尽管这不是一种干净的方法。

包括适当的头文件以避免未定义的行为。

相关内容

  • 没有找到相关文章

最新更新