【问题标题】:can anybody help me to solve this pointer question in c谁能帮我在c中解决这个指针问题
【发布时间】:2021-06-10 14:41:28
【问题描述】:

谁能帮我理解这段代码(c)..

#include <stdio.h>

void main()

{

   const int a =5;int b;

   int *p;

   p= (int *) &a;



  b=a;



   *p= *p +1;

   printf(" value of p is = %d\n", *p);  

   printf(" value of b is = %d\n", b);

   printf(" value of a is = %d\n",a);

}

结果是

: p 的值为 = 6

: b 的值为 = 5

: a 的值为 = 6

【问题讨论】:

  • 此代码错误,因为它修改了const 变量。它可能会给出其他结果而不是此处显示的结果,甚至崩溃。
  • @interjay 解释这个ideone.com/3wfWlL
  • @BeshambherChaukhwan 未定义的行为意味着任何事情都可能发生,这就是为什么你得到的结果与 OP 不同。
  • 嗯,所以这意味着任何事情都可能发生????酷
  • @BeshambherChaukhwan:从技术上讲,未定义的行为意味着编译器和运行时环境都不需要以任何特定方式处理这种情况。实际结果可能取决于平台、编译器、任何优化标志、周围代码、运行时环境等,不保证可重复或可预测。

标签: c pointers constants


【解决方案1】:

使用指令p = (int *)&amp;a;,您使p 指向a
结果表达式*p 引用变量a,因此*p = *p + 1; 等效于a = a + 1; – 变量a 被赋予其先前的值(即5)加1。
所以终于到了 6 点。

然而,这是一种未定义的行为,正如@interjay 在this comment 中指出的那样——a 变量被声明为const,这意味着它不能被修改。因此,编译器可能会选择将其分配到内存的只读区域中。在您的情况下它没有,并且分配成功,但在其他情况下,变量的修改可能会静默失败(a 值剩余 5)或产生内存访问异常(并终止程序)或其他任何情况。

【讨论】:

  • 请注意 aconst 所以修改它是未定义的行为。
  • @interjay 但是值增加了,不是吗?所以通过指针的赋值就像它可以直接做的那样工作。当然,作为一个 UB,它可能会失败或做任何其他事情,但在这种情况下,它等同于直接分配给一个(非常量)变量。
  • UB 可以是任何东西,包括预期的结果。但它不能被依赖,否则建议是错误的。当我测试 OP 的代码时,我得到了不同的结果。
  • @interjay 你是对的。我已经扩展了我的答案..
【解决方案2】:

这段代码的目的是通过指针p更新a的值。让我们去掉一些东西,从基础开始:

int a = 5; 
int *p = &a;

我们有一个名为a 的对象,它存储整数值5。我们有另一个名为p 的对象,它存储a地址。在上面的两个声明之后,满足以下条件:

 p == &a  == some address value 
*p ==  a  == 5

表达式 *p 等价于表达式 a - 为*p 分配一个新值与为a 分配一个新值相同,所以

*p = *p + 1

和写一样

a = a + 1

但是,在您发布的代码中 a 已声明为 <em>const</em> int。这意味着您告诉编译器 a 的值不应在其生命周期内改变。编译器将标记任何语句,如

a = a + 1

a++;

作为一个错误。编译器可能也将a 存储在只读内存中;如果你从不使用a 的地址(也就是说,如果它不是一元&amp; 的操作数),编译器可能不会为它保留任何存储空间 > 并且只需将它的任何实例替换为值(IOW,您希望在机器代码中看到对 a 的引用的任何地方,您只会看到文字 5),这意味着根本没有什么可写的。

但是这段代码作弊 - 它把p 声明为一个指向-constint 的指针。 表达式 &amp;a的类型是const int *(指向const int的指针),但p的类型只是int *(指向int的指针)。在作业中

p = (int *) &a;

您正在抛弃a 上的const 限定符。因此,当您向 *p 写入新值时,编译器不知道您正在尝试修改声明为 const 的内容,因此它不会将其标记为错误.

C 语言定义说,尝试通过非const-qualified 左值更新const-qualified 对象1 会导致未定义的行为 -编译器不需要以任何特定方式处理这种情况。结果可以是以下任何一项:

  • 运行时错误;
  • a的值保持不变;
  • 表现完全符合预期;

或完全不同的东西。


  1. 左值是指定对象以便可以读取或修改对象的任何表达式。 a*p 都是左值,它们引用包含值 5 的整数对象

【讨论】:

    【解决方案3】:

    在解释之前,让我告诉你,这部分有点问题,并且可能导致未定义的行为:

    const int a =5;
    p= (int *) &a;
    

    您应该删除const,因为在这种情况下您想通过指针修改a 的内容。一些编译器(例如 clang,正如 cmets 中有人提到的)可能会执行优化,例如将使用 const 变量的位置替换为它的值,以减少内存访问操作的数量。


    让我们假设每个变量都是一个小盒子,您可以在其中放置数字。所以你有 3 个盒子:

    +---+   +---+   +---+
    | 5 |   |   |   |   |
    +---+   +---+   +---+
      a       b       p
    

    现在让我们回顾一下每个语句,看看发生了什么。

       int *p;
    
       p= (int *) &a;
    

    p被定义为一个指针,它是一种变量,可以保存内存中某物的地址。在这种情况下,它被分配了变量a 的地址。所以我们的盒子现在看起来像这样:

      +---------------+
      v               |
    +---+   +---+   +----+
    | 5 |   |   |   | &a |
    +---+   +---+   +----+
      a       b       p
    

    p 只包含a 的内存地址。您可以使用printf("%u", a) 打印它,您会看到一些数字。那是a的地址。

      b=a;
    

    这里我们将a的值复制到b,所以我们的盒子变成了:

      +---------------+
      v               |
    +---+   +---+   +----+
    | 5 |   | 5 |   | &a |
    +---+   +---+   +----+
      a       b       p
    

       *p= *p +1;
    

    使用*p 语法,我们可以取消引用指针,这意味着我们可以访问p 指向的内存(按照箭头)。在这种情况下,*p 将允许我们获取或设置 a 变量的内容。我们的盒子现在变成了这样:

      +---------------+
      v               |
    +---+   +---+   +----+
    | 6 |   | 5 |   | &a |
    +---+   +---+   +----+
      a       b       p
    

       printf(" value of p is = %d\n", *p);  
    

    在这里你再次取消引用 p,这意味着我们正在获取地址 p 的内存内容。在我们的例子中,这将获得a 变量的内容,即6

       printf(" value of b is = %d\n", b);
    

    查看b框,我们可以看到它包含5

       printf(" value of a is = %d\n",a);
    

    我们使用指针修改了a。查看a 框,我们可以看到它包含值6

    【讨论】:

    • 很好地解释了指针。但是,请注意 aconst 所以修改它是未定义的行为。当我用 clang 运行它时,a 仍然包含值 5。
    【解决方案4】:

    一行一行

    const int a =5;int b;
    

    在这一行中,变量b被定义为int,变量a被定义为const int,这意味着它的值在所有较低的步骤中都是恒定的,并且等于5。

    int *p;   
    p= (int *) &a;
    

    在这两行中,一个名为p的变量被定义为一个指针int,其值(必须是来自内存单元的地址)等于变量a的地址。 这意味着变量 a 和 p 都指向一个公共存储单元。 换句话说:

    (*p == a) //IS TRUE. Both are equal to 5
    

    下一行:

      b = a;
    

    即变量b的值也等于a,等于5

    *p= *p +1;
    

    在此行中,将一个单位添加到与地址p 对应的值。 我们知道变量 a 和 p 指向一个共同的记忆单元。 其实这意味着我们间接给变量a加了一个单位,也就是说这两个变量的值都是(5 + 1)。

    最后,最后三行输出的原因很清楚了

    【讨论】:

      【解决方案5】:

      问题完全出在下面一行:

      p= (int *) &a;
      

      如果没有类型转换,该行将显示为:

      p = &a;
      

      a 的类型是const intp 的类型是int *

      很明显,编译器应该警告丢弃const 限定符:

      警告:从 'const int *' 分配给 'int *' 会丢弃限定符 [-Wincompatible-pointer-types-discards-qualifiers]

      这说明了为什么您应该始终尽量避免显式类型转换(除非绝对必要)。这段代码的作者自爆了。他们引入了未定义的行为,并且隐藏了明显的问题,因为警告被丢弃或抑制

      【讨论】:

        猜你喜欢
        • 2012-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 2021-11-13
        • 2022-12-03
        相关资源
        最近更新 更多