首页 > 解决方案 > 在 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;
}

我真正需要知道的是为什么这段代码在旧服务器上运行良好,我忽略了什么?我可以更改代码以使用普通数组使其在新服务器上运行,但这会导致什么样的问题?

标签: csolariscc

解决方案


请注意,您没有char blank[],而是char *blank,它指向字符串文字。字符串文字是不可变的。此代码试图修改 所指向的文字的字符之一blank,从而导致未定义的行为。未定义行为的有趣之处在于它可以做任何事情,包括按照您的预期方式运行。

还值得注意的是,字符串文字已经隐式地以空值结尾,因此无论如何都不需要在末尾显式添加 '\0'。


推荐阅读