5

char *strtok(c​​har *s1, const char *s2)

对该函数的重复调用将字符串 s1 分解为“标记”——即字符串被分解为子字符串,每个子字符串以 '\0' 结尾,其中 '\0' 替换字符串 s2 中包含的任何字符。第一次调用使用要标记为 s1 的字符串;随后的调用使用 NULL 作为第一个参数。返回指向当前标记开头的指针;如果没有更多标记,则返回 NULL。

你好,

我刚才一直在尝试使用strtok,发现如果我传入一个char*into s1,我会得到一个分段错误。如果我通过 a char[]strtok工作正常。

为什么是这样?

我四处搜索,原因似乎是关于如何char*只读和char[]可写的。更彻底的解释将不胜感激。

4

5 回答 5

15

你初始化了char *什么?

如果像

char *text = "foobar";

然后你有一个指向一些只读字符的指针

为了

char text[7] = "foobar";

然后你有一个七元素的字符数组,你可以做你喜欢的事情。

strtok写入您给它的字符串 - 用分隔符覆盖null并保留指向字符串其余部分的指针。

因此,如果您将只读字符串传递给它,它将尝试写入它,并且您会得到一个段错误。

此外,因为strtok保留了对字符串其余部分的引用,所以它不是可重入的 - 您一次只能在一个字符串上使用它。最好避免,真的 - 请考虑 strsep(3) - 例如,请参见:http ://www.rt.com/man/strsep.3.html (尽管它仍然写入字符串,因此具有相同的读取-仅/段错误问题)

于 2008-11-07T17:40:59.053 回答
6

推断但未明确说明的重要一点:

根据您的问题,我猜您对 C 编程相当陌生,所以我想多解释一下您的情况。如果我弄错了,请原谅我;C 可能很难学习,主要是因为对底层机制的微妙误解,所以我喜欢让事情尽可能简单。

如您所知,当您编写 C 程序时,编译器会根据语法为您预先创建所有内容。当您在代码中的任何位置声明变量时,例如:

int x = 0;

编译器读取这行文本并对自己说:好的,我需要将当前代码范围内的所有出现替换为x对我分配用于保存整数的内存区域的常量引用。

当你的程序运行时,这一行会导致一个新的动作:我需要设置x引用intvalue的内存区域0

请注意这里的细微差别:参考点所在的内存位置x是恒定的(并且不能更改)。但是,x可以更改点的值。您可以通过分配在代码中执行此操作,例如x = 15;. 另请注意,单行代码实际上相当于编译器的两个单独命令。

当您有如下声明时:

char *name = "Tom";

编译器的过程是这样的:好的,我需要将当前代码范围中的所有出现替换为name对我分配用于保存char指针值的内存区域的常量引用。它确实如此。

但是还有第二步,这相当于:我需要创建一个常量数组,其中包含值 'T'、'o'、'm' 和NULL。然后我需要用"Tom"该常量字符串的内存地址替换代码的一部分。

当你的程序运行时,最后一步发生:将指向char' 值的指针(不是常量)设置为自动创建的字符串的内存地址(它常量)。

所以 achar *不是只读的。只有 aconst char *是只读的。但是在这种情况下,您的问题不是char *s 是只读的,而是您的指针引用了只读的内存区域。

我提出这一切是因为理解这个问题是您从库中查看该函数的定义和自己理解问题与不得不问我们之间的障碍。我已经稍微简化了一些细节,希望让这个问题更容易理解。

我希望这可以帮到你。;)

于 2008-11-08T19:22:22.107 回答
2

我责怪C标准。

char *s = "abc";

可以定义为给出相同的错误

const char *cs = "abc";
char *s = cs;

因为字符串文字是不可修改的。但它不是,它被定义为编译。去搞清楚。[编辑:Mike B 已经想通了——K&R C 中根本不存在“const”。ISO C 以及此后的每个版本的 C 和 C++,都希望向后兼容。所以它必须是有效的。]

如果它被定义为给出错误,那么你就不可能达到段错误,因为 strtok 的第一个参数是 char*,所以编译器会阻止你传入从文字生成的指针。

可能有趣的是,曾经有一个 C++ 计划要弃用它(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0896.asc)。但是 12 年后,我无法说服 gcc 或 g++ 给我任何警告,让我将文字分配给非常量 char*,所以它并没有被大声反对。

[编辑:啊哈:-Wwrite-strings,不包含在 -Wall 或 -Wextra 中]

于 2008-11-07T19:34:40.413 回答
0

简单来说:

char *s = "HAPPY DAY";
printf("\n %s ", s);

s = "NEW YEAR"; /* Valid */
printf("\n %s ", s);

s[0] = 'c'; /* Invalid */
于 2009-02-21T01:21:53.783 回答
0

如果您查看编译器文档,很可能有一个选项可以设置为使这些字符串可写。

于 2009-02-21T01:45:35.940 回答