我正在尝试理解为什么下面的代码片段会给出一个分段错误:
void tokenize(char* line)
{
char* cmd = strtok(line," ");
while (cmd != NULL)
{
printf ("%s\n",cmd);
cmd = strtok(NULL, " ");
}
}
int main(void)
{
tokenize("this is a test");
}我知道strtok()实际上不会对字符串文字进行标记化,但在本例中,line直接指向字符串"this is a test",该字符串在内部是一个char数组。是否可以在不将line复制到数组中的情况下对其进行标记化?
发布于 2012-01-22 08:22:39
问题是您正在尝试修改字符串文字。这样做会导致您的程序的行为是未定义的。
说不允许修改字符串文字是过于简单化了。说字符串字面值是const是不正确的,其实不然。
警告:后面跟着分题。
字符串文字"this is a test"的表达式类型为char[15] (14表示长度,1表示终止'\0')。在大多数上下文中,包括这个表达式,这样的表达式被隐式转换为指向数组第一个元素的指针,类型为char*。
试图修改string文本引用的数组的行为是未定义的--不是因为它是const (它不是),而是因为C标准明确规定它是未定义的。
一些编译器可能会允许您逃脱这一点。您的代码实际上可能会修改与文本相对应的静态数组(这可能会在以后造成很大的混乱)。
不过,大多数现代编译器都会将数组存储在只读内存中--不是物理ROM,而是存储在受虚拟内存系统保护的内存区域中。尝试修改这种内存的结果通常是分段错误和程序崩溃。
那么为什么字符串文字不是const呢?既然您真的不应该尝试修改它们,那么这样做肯定是有意义的--而且C++确实将字符串字面值设为const。原因是历史的。在1989年的ANSI标准引入const关键字之前,它并不存在(尽管在此之前,一些编译器可能已经实现了它)。因此,ANSI之前的程序可能如下所示:
#include <stdio.h>
print_string(s)
char *s;
{
printf("%s\n", s);
}
main()
{
print_string("Hello, world");
}print_string不允许修改s所指向的字符串,这一事实是无法强制执行的。在ANSI中使用const会破坏现有的代码,这是ANSI委员会极力避免的。从那时起,就没有一个很好的机会对语言进行这样的更改。( C++的设计者,主要是Bjarne Stroustrup,并不关心与C的向后兼容性。)
发布于 2012-01-22 08:04:41
Strok修改了它的第一个参数,以便对其进行标记化。因此,您不能向它传递文字字符串,因为它的类型是const char *,并且不能修改,因此出现了未定义的行为。您必须将字符串文字复制到可修改的char数组中。
发布于 2012-01-22 08:02:45
正如您所说的,您不能修改字符串文字,而这正是strtok所做的。你必须这样做
char str[] = "this is a test";
tokenize(str);这将创建数组str并使用this is a test\0对其进行初始化,然后将指向该数组的指针传递给tokenize。
https://stackoverflow.com/questions/8957829
复制相似问题