我正在编写代码以加强我的知识,我得到了分段错误。所以,我也得知我必须补充(完成不完全的知识)我的知识。问题是关于strtok()
。当我运行第一个代码没有问题,但在第二个,我得到segmantation错误。什么是我不完美的知识" ?谢谢你的赞赏。
第一个代码
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "team_name=fenerbahce";
char *token;
token = strtok(str,"=");
while(token != NULL)
{
printf("%s\n",token);
token = strtok(NULL,"=");
}
return 0;
}
第二个代码
#include <stdio.h>
#include <string.h>
int main() {
char *str= "team_name=fenerbahce";
char *token;
token = strtok(str,"=");
while(token != NULL)
{
printf("%s\n",token);
token = strtok(NULL,"=");
}
return 0;
}
答案 0 :(得分:3)
来自strtok -
这个功能是破坏性的:它写了&#39; \ 0&#39;字符串str的元素中的字符。特别是,字符串文字不能用作strtok的第一个参数。
在第二种情况下,str
是一个字符串文字,它位于只读内存中。任何修改字符串文字的尝试都会导致未定义的行为。
答案 1 :(得分:1)
char *str= "team_name=fenerbahce";
char str[]= "team_name=fenerbahce";
“不完美”的知识是关于数组和指针之间的区别!它是关于使用指针创建字符串时无法修改的内存。 创建字符串时,您会分配一些内存来存储这些值(字符串的字符)。在接下来的几行中,当我谈到“开始时分配的内存”时,我会参考这个。
使用数组创建字符串时,您将创建一个数组,该数组包含与字符串相同的字符。所以你会分配更多的内存。
使用指针创建字符串时,您将指向指向包含该字符串的内存地址(在开始时分配的字符串)。
您必须假设在开始时创建的内存不可写(这就是为什么您将有未定义的行为,这意味着大多数时候都会出现分段错误,所以不要这样做)。 相反,当您创建数组时,该内存将是可写的!这就是为什么你只能在这种情况下使用像strtok这样的命令进行修改
答案 2 :(得分:1)
你看到字符串文字是你在“”中写的字符串。对于每个这样的字符串,无论在何处使用它,都会自动地全局空间来存储它。将其分配给数组时 - 将其内容复制到新数据库的内存中。否则,您只需存储指向其全局内存存储器的指针。
所以这个:
int main()
{
const char *str= "team_name=fenerbahce";
}
等于:
const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
int main()
{
const char *str= __unnamed_string;
}
将字符串分配给数组时,如下所示:
int main()
{
char str[] = "team_name=fenerbahce";
}
对此:
const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
int main()
{
char str[sizeof(__unnamed_string) / sizeof(char)];
for(size_t i(0); i < sizeof(__unnamed_string) / sizeof(char); ++i)
str[i] = __unnamed_string[i];
}
正如您所看到的,存在差异。在第一种情况下,你只是存储一个指针而在第二种情况下 - 你将整个字符串复制到本地。
注意:字符串文字是不可编辑的,因此您应将其地址存储在常量中。
在N4296 - §2.13.5.8中指出:
也引用普通的字符串文字和UTF-8字符串文字 作为窄字符串文字。窄字符串文字的类型为“数组” of n const char“,其中n是下面定义的字符串的大小, 并具有静态存储持续时间
这个决定背后的原因可能是因为这样,这样的数组可以存储在只读段中,从而以某种方式优化程序。有关此决定的更多信息see。
注1 :
在N4296 - §2.13.5.16中指出:
评估字符串文字会产生字符串文字对象 静态存储持续时间,从给定字符初始化为 以上具体说明。
这正是我所说的 - 对于每个字符串文字,一个未命名的全局对象是用它们的内容创建的。