【问题标题】:Why the location pointed by a pointer to const is assignable by other variable?为什么指向 const 的指针指向的位置可以由其他变量分配?
【发布时间】:2018-01-28 06:13:29
【问题描述】:

这段代码我已经写好了

#include <stdio.h>
int main() {
     int b = 15;
     const int *foo = &b;
     //b = 20;
     *foo = 20;
     printf("%d", *foo);
     return 0;
}

这意味着foo 指向的位置不能改变。这意味着 b 无法更改。但是当我取消注释b = 20 时。它没有显示任何错误,我得到了输出 20 。在这段代码中,我收到此错误

main.c: In function 'main':
main.c:15:10: error: assignment of read-only location '*foo'
      *foo = 20;

如果*foob是只读位置,为什么我可以更改它的值b = 20

【问题讨论】:

  • 看看this answer,我相信它会帮助你理解它为什么会这样做
  • 您不能使用foo 来更改它所指向的内容。没有什么可以阻止您更改其他合法机制所指向的内容。使用b 是修改foo 指向的位置的合法机制。
  • 请阅读整个问题!
  • @PradeepKumar 是否堆栈段有写保护区域?如果是这样,它将需要典型堆栈帧的许多碎片区域(在某些实现中)。我的理解是它是对编译器的指令。

标签: c pointers


【解决方案1】:

这个问题的答案是在声明指针为之后

const int *foo = &b;

您不能使用 *foo 作为 L 值,因为此代码也会给出相同的错误

#include <stdio.h>
int main() {
     int a=10,b = 15;
     const int *foo = &b;
     foo=&a; //assigning foo the address of a
     *foo=30; // Again here you cant use *foo
     printf("%d", *foo);
     return 0;
}

【讨论】:

    【解决方案2】:

    是什么

     int b=15;
     const int* foo=&b;   
    

    是什么意思?

    意思是,

    • b 是一个可修改的 int 对象。
    • &amp;b 的类型为 int *foo 的声明将 &amp;b 转换为类型 const int *。这是一个有效的资格转换。
    • foo 指向的 int 对象不得使用 foo 修改。

    上述资格转换不会使b的声明无效,即它仍然是可修改的b 仍可用于更新其值,但 *foo 无法使用。

    const 视为一种承诺。您向编译器承诺您不会更改foo 指向的位置的值,但没有人会阻止您通过其他方式更改该位置的值来破坏该承诺。

    【讨论】:

    • 这就是问题所在。 foo 指向 b 。我可以将它设置为 b=20 并且我没有收到任何错误!
    • 您不能使用foo 来更改它所指向的内容。没有什么可以阻止您更改其他合法机制所指向的内容。使用b 是修改foo 指向的位置的合法机制。
    • b 只是存储在内存中的值的名称(内存中的位置)。错误说是只读的。那我们怎样才能改变它的价值呢?抱歉,我没听懂!
    • @PradeepKumar:我们可以看到你没有得到它。很难弄清楚为什么你没有得到它。 foo 是一个指向常量值的指针,这意味着您不能使用 foo 来更改它所指向的内容。但是b 不是恒定的。它可以改变。它只是无法使用foo 更改。
    • @PradeepKumar;我更改了答案并进一步解释。再读一遍。
    【解决方案3】:

    我认为 chqrlie 说的错误消息“只读位置 '*foo' 的分配”具有误导性是正确的。实际上,const int *foo(即定义为指向const int 的指针)并不意味着指针所寻址的内存本身是不可变的;它只是意味着指针所寻址的内存不能通过这个指针改变;但是,它可能会以其他方式进行更改。例如,您可以定义第二个指针int *foo2 = &amp;b,通过它您可以更改foo2 寻址的值。

    因此,您可能会将指针视为特定内存地址上的值的单独视图,并且可以将视图声明为只读或非只读。但是,这不会影响特定内存地址本身的值是否不可变:

    int main()
    {
        int b=15;  // b is mutable
        const int* foo=&b; // *foo is immutable; b remains mutable
        int *foo2=&b; // *foo2 is mutable
        b=20;  // allowed, since b is mutable
        *foo=20; // not allowed, since "*foo" is immutable, even if the value to which it points (i.e. b) would be mutable
        *foo2=20; // allowed, since "*foo2" is mutable
    
        return 0;
    }
    

    虽然没有被问到,但反过来说,您实际上可以将 定义为不可变的,并且该值不得以任何方式更改;如果您以某种方式通过写入其内存地址来操纵该值,则行为未定义:

    const int c = 15; // c is immutable
    int* bar = &c; // warning: discards const qualifier
    printf("%d\n", c);
    *bar = 20;  // undefined behaviour from here on; modifying a const value is not allowed.
    printf("%d\n", c); // undefined behaviour; good chance that it still prints 15, because a compiler might have relied on the fact that c is 15 and immutable
    printf("%d\n", *bar); // undefined behaviour; probably printing 20?
    

    希望对你有帮助。

    【讨论】:

    • 感谢您的回答,但我们如何才能拥有主内存的两个单独视图!
    • 如果你愿意,你可以有任意多的指针,都指向同一个主存地址。
    • @PradeepKumar 指针只是一个变量,它保存其他东西的地址作为其值。您可以有许多指针都持有相同的地址(指向相同的其他东西)。 “views”可能不是最好的词,但它准确地描述了您通过多个指针查看内存中相同位(如果它们都指向这些位)的能力。
    【解决方案4】:

    不,const int* foo = &amp;b; 并不意味着你不能改变b,这意味着你不能像这样取消引用这个指针并改变被取消引用的指针的值

    *foo = 20;
    

    你不能用const 说某些内存对所有人都是不可修改的。你可以说只有const这个变量不能改变这块内存,所以这个操作(如果b没有const修饰符)是完全有效的,即使你有指向b的const指针。

     b=20;
    

    【讨论】:

    • @Filip Kočica IMO 它是“T” - 单词问题
    • @PradeepKumar:错误消息显示*foo 是只读位置,因为foo 被定义为指向不应通过此指针更改的位置。错误信息有些混乱。
    • @chqrlie:好点,错误信息具有误导性,很可能是 OP 误解代码含义的根本原因。
    • 指针声明和对象声明是有区别的。指针不能用于更改引用的对象。对象本身可以更改,但不能通过 const 指针
    • 这里的重点是指向非常量的指针可以无缝地转换为指向相同类型的常量的指针。这被解释为不打算通过这个指针修改值。当然,原始的左值不会受到向它添加新指针的影响,并且仍然可写。
    【解决方案5】:

    如果你想要一个指向非常量对象的常量指针声明它:

     T * const ptr = &t
    

    T 是对象的类型,t 是对象本身

    【讨论】:

    • 这不是我要问的!
    • 请库马尔停止大喊:D
    • 所以学习如何提问。 Constant Pointers 表示常量指针而不是指向常量对象的指针。责备自己并感谢有人浪费时间回答您的问题
    • 我承认我的错误。但是您应该阅读整个问题并建议进行编辑。还是谢谢!
    猜你喜欢
    • 1970-01-01
    • 2015-09-10
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多