c - 在 C 中编辑不可变字符串 - 与旧编译器一起使用,但与现代编译器中断
问题描述
我正在处理一些在 Solaris 10 上运行的古老遗留代码。在旧服务器上,代码编译并运行没有问题。
然后将代码迁移到 Solaris 11 服务器,代码仍然可以在其中编译,但在运行时会创建一个 seg fault 核心转储。
在这两种情况下,使用的编译器都是 /opt/SUNWspro/bin/cc。
这是代码片段:
#include <stdio.h>
char *blank = " ";
main(argc,argv)
int argc;
char **argv;
{
blank[35] = '\0';
printf("Success.\n");
}
这在 Solaris 10 上有效,但在 Solaris 11 上会导致分段错误(核心转储)。通常我会说当空白 [] 数组仅上升到时尝试写入空白 [35] 导致分段错误空白[34](它用 35 个空格字符初始化),除了此代码在 Solaris 10 上工作。
另外,当我将行更改为 'blank[34] = '\0';' 在新服务器上,我仍然得到一个段错误核心转储。
当我将空白更改为普通数组(并且还对 main 进行现代化改造)时,一切正常,正如我所料:
#include <stdio.h>
char blank[35];
int main(int argc,char **argv)
{
int i;
for (i=0; i<34; i++)
{
blank[i] = ' ';
}
blank[34] = '\0';
printf("Success.\n");
return 0;
}
我真正需要知道的是为什么这段代码在旧服务器上运行良好,我忽略了什么?我可以更改代码以使用普通数组使其在新服务器上运行,但这会导致什么样的问题?
解决方案
请注意,您没有char blank[]
,而是char *blank
,它指向字符串文字。字符串文字是不可变的。此代码试图修改 所指向的文字的字符之一blank
,从而导致未定义的行为。未定义行为的有趣之处在于它可以做任何事情,包括按照您的预期方式运行。
还值得注意的是,字符串文字已经隐式地以空值结尾,因此无论如何都不需要在末尾显式添加 '\0'。
推荐阅读
- javascript - 完成 Google 表单后,如何在 Google 电子表格中现有工作表的末尾创建新行?
- python - numpy genfromtxt 读取 csv 的第一个值是否丢失?
- css - 加载第二个样式表不起作用(Shopify)
- oop - 是否可以从父类调用子类中的覆盖方法?
- r - 从r中的url中提取字符串
- angular6 - Angular6 - 自定义输入字段
- function-pointers - 在 C 中打印任何数据类型的二维数组的通用函数
- javascript - 如果文本匹配字符串,如果文本不匹配字符串
- javascript - 如何在 VSCode 上的 .js 文件中获取 GraphQL 语法功能?
- git - 包括 github 项目的许可证