【问题标题】:Replacing (not modifying) 'const' values, legal?替换(不修改)'const'值,合法吗?
【发布时间】:2021-12-30 20:43:07
【问题描述】:

观察以下代码:

const char *str1 = "foo";
printf("1.1: %s\n", str1);
str1 = "bar";
printf("1.2: %s\n\n", str1);

const char *str2[] = { "foo", "bar" };
printf("2.1: %s\n", str2[0]);
str2[0] = "baz";
printf("2.2: %s\n\n", str2[0]);

char *str3 = malloc(4);
strcpy(str3, "foo"); 
const char *str4[] = { str3, "bar" };
printf("3.1: %s -- %s\n", str4[0], str4[1]);
//str4[0][0] = 'z';
str4[0] = "bar";
str4[1] = "baz";
printf("3.2: %s -- %s\n", str4[0], str4[1]);
free(str3);

将其包装在标准的main 函数中并使用gcc -Wall -Wextra -o test test.c 进行编译,这不会给出警告,输出为:

1.1: foo
1.2: bar

2.1: foo
2.2: baz

3.1: foo -- bar
3.2: bar -- baz

当取消注释唯一的注释行时,gcc 会抱怨 error: assignment of read-only location ‘*str4[0]’。当然这是意料之中的,我只是为了完整而添加了那一点。

据我了解,所有其他分配都是有效的,因为我没有修改已经存在的只读内存,而是将其全部替换为 另一个 内存块(这也是标记为只读)。但这在所有 C 编译器中都是合法的,还是仍然依赖于实现,因此会导致未定义的行为?很难找到这方面的好信息,因为它似乎总是关于通过指针魔术修改现有内存或将const 扔掉。

【问题讨论】:

  • 您不是在“替换”内存,而是在使指针指向不同的内存位置。该操作是有效的,因为指针本身不是const
  • 您不是在修改或“替换”(无论这意味着什么)任何只读内存——您正在修改不是 const 的指针,因此不在只读内存中。您可能在脑海中混淆了指针的内存和指针指向的内存——这是两个不同的位置。
  • 是的,我不知道怎么称呼它,“替换”我的意思是“让它指向不同的(只读)内存”。我并不是要暗示相同的内存部分被不同的内容替换。

标签: c pointers constants declaration string-literals


【解决方案1】:

在此声明中

const char *str1 = "foo";

指针(变量)str1 不是常量。指针str1 指向的字符串文字是常量。即(非常量)指针str1 指向const char 类型的常量对象。

所以你不能改变指针所指向的文字,例如

str1[0] = 'g';

但您可以更改变量 str1 本身,因为它不是常量

str1 = "bar";

要将指针str1 声明为常量指针,您应该编写

const char * const str1 = "foo";

在这种情况下你可以不写

str1 = "bar";

因为现在指针str1 本身是常量。

请注意,尽管在 C 中字符串文字具有非常量字符数组的类型,但您不能更改字符串文字。任何更改字符串文字的尝试都会导致未定义的行为。

那是你可能不会写

char *str1 = "foo";
str1[0] = 'g';

【讨论】:

  • 这是我一直在寻找的答案。我知道您不应该更改文字,并且一旦编译的程序到达该部分,它可能只会引发总线错误。我不知道如何使指针 它们自己 保持不变。所以看起来我的示例确实是有效的标准 C,因此它在所有编译器中的工作方式应该完全相同。如果您可以对此稍加提及,那么我可以接受您的回答。 :>
  • @Sahbi 答案中写得很清楚“但是您可以更改变量 str1 本身,因为它不是恒定的”
  • 是的,我知道,但问题是“这在所有 C 编译器中都是合法的,还是它仍然依赖于实现,因此会导致未定义的行为”并且它并没有明确回答.可能看起来有点迂腐,但我认为它可以提供更好的答案。
猜你喜欢
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多