为什么下面的代码会出现段错误?
#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);
为tmp
和first
打印的地址应该相同(如果您#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
的行为是这样的:
- 接受字符串
str
或 NULL 以及分隔符字符串。 - 然后strtok函数开始处理给定的字符串
str
,其中它逐个字符读取字符串,直到它遇到在提供的分隔符字符中存在的字符。 - 如果在到达分隔符字符串之前遇到的字符数> 0,则将分隔符替换为"",并返回指向此迭代中第一个不是分隔符字符的指针。
- 否则,如果在到达分隔符字符串之前遇到的字符数为 == 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 字节的类型(在我的情况下很长(,那么就不会有段错误,尽管这不是一种干净的方法。
包括适当的头文件以避免未定义的行为。