【问题标题】:What is the difference between "int *p =0;" and "int *p; *p=0;""int *p =0;" 和有什么区别和“int *p;*p=0;”
【发布时间】:2019-11-06 00:14:36
【问题描述】:

试图弄清楚指针初始化和指针赋值之间的区别。

C语言

int *p=0;
int *p;
*p=0;

我不知道这两种方法有什么区别。一样吗?

【问题讨论】:

  • 第二种情况是未定义行为,第一种是违反约束。
  • @SouravGhosh 第一个是正确的
  • @M.M 怎么样?
  • @SouravGhosh 存在从值0 的整数常量表达式到任何指针类型的隐式转换
  • 作为一个额外的练习,您可能会想如果将static 添加到它们两者会发生什么。

标签: c pointers initialization variable-assignment declaration


【解决方案1】:

两者是不同的。这里

int *p=0;

整数指针p被赋值为0,这与

int *p; /* first p is declared : uninitialized */
p = 0; /* then assigned with 0 */

虽然我不喜欢p = 0。这个

int *p = NULL;

更好。 还有这里

int *p; 
*p=0; /* p doesn't have any valid address, de-referencing it causes UB */

您试图将*p 分配给0,这是错误的,因为在这种情况下p 没有任何有效地址。它调用未定义的行为

【讨论】:

  • 表示第一个方法指向No.0单元,第二个方法指向某个未知的地方,然后将值0赋给未知单元,赋值行为本身是错误的,不允许?
  • 是的,因为p 在第二种情况下没有指向有效的内存位置,即当编译器执行*p 时,它会调用未定义的行为。
【解决方案2】:
int *p=0;

这一行将声明int * 指针并使其指向0。还要确保在取消引用之前使p 指向有效内存。

int *p;
*p=0;

是未定义的行为。因为p 没有指向任何地方。

【讨论】:

    【解决方案3】:

    在函数内,

    int *p = 0;
    

    相当于:

    int *p;
    p = 0;
    

    即变量本身被初始化,声明的声明部分被忽略。相对于:

    int *p;
    *p = 0;
    

    这会导致未定义的行为,因为未定义指针的 目标 被分配给。

    【讨论】:

      【解决方案4】:

      指针初始化和指针赋值没有区别。除了可以将指针声明及其初始化放在全局名称空间中,而作为表达式语句的赋值只能在函数内部使用。

      所以总的来说这两个代码sn-ps的效果是一样的。

      int *p = 0;
      

      int *p;
      p = 0;
      

      您错误地将指针指向的对象赋值视为指针本身的赋值。

      在此声明中

      *p=0;
      

      指针被解除引用,指针指向的对象被赋值为0。

      int *p;
      *p=0;
      

      由于指针本身未初始化,因此它具有一些不确定的值,并且带有赋值表达式的表达式语句具有未定义的行为。

      考虑下面的代码sn-p

      int x;
      int *p;
      
      p = &x; // pointer assigment
      *p = 0; // object assignment pointed to by the pointer
      

      对指针类型使用 typedef 将有助于避免指针赋值和指针指向的对象赋值之间的混淆

      例如

      typedef int * Pointer;
      
      Pointer p;
      p = 0;
      

      所以在声明中,'*' 符号用于声明指针。

      在表达式中,符号'*' 表示表示间接的一元运算符。将此运算符应用于指针的结果是指定对象的左值。

      【讨论】:

        【解决方案5】:

        每个新的 C 程序员都在为指针苦苦挣扎的主要原因是指针声明和指针访问/取消引用之间看起来相似的语法。

        • int *p; 是一个指向整数的指针的声明。
        • *p=0; 正在取消引用指针,访问它指向的位置并尝试在那里写入值 0。为此,必须首先将指针设置为指向有效的内存位置。
        • int *p = 0; 是一个指向整数的指针的声明,带有一个初始值设定项。这将设置 指针本身 指向的位置。它不是取消引用。

        将值0 分配/初始化给指针本身是一种特殊情况,因为这会转换为“空指针常量”。基本上是一个指向明确定义的无处的指针。最好使用 stddef.h 中的宏 NULL 代替,这样我们就不会将它与整数值 0 混淆。

        因为*p=0; 单独一行,所以0 就是这样,一个普通的整数值。

        另见Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer

        【讨论】:

        • 这是当前作物中唯一不错的答案。
        【解决方案6】:
        int *p = 0;
        

        这将创建一个指向地址零的整数指针。所以它是一个空指针。空指针只是意味着指针没有指向任何东西,或者在某些语言中意味着它不知道它指向什么。但是因为是空指针,你知道这个,代码也知道这个,所以没问题。

        一个未初始化的指针变量通常被称为悬空指针,因为你不知道它指向哪里。表演

          int *p;
            *p=0;
        

        具有不可预测的影响。

        【讨论】:

          【解决方案7】:

          快速解答

          它们是不同的,因为在您的第一个示例int *p=0; 中,您将 p 声明为指针,然后将其设置为指向地址 0x0。这一行例子相当于这两行代码int *p; p=0;

          在您的第二个示例int *p; *p=0; 中,您在第一行声明了 p,但它没有初始化......所以 p 指向未定义的某个地方。在第二行中,您将转到该未定义位置的地址并尝试将该地址的值设置为 0。

          您可以看到此示例与之前等效的两行示例之间的区别,因为一个使用p=0;,另一个使用*p=0;

          示例

          因此,在您尝试访问 *p 之前,您需要定义 p 指向的位置。假设您知道要 p 指向的整数的地址是 0x76543210。让我们看一下代码运行之前内存中的值:

          //  Dummy Memory Dump
          //   Offset:      0        4        8        C
          //  (0x76543200): 00000000 00000000 00000000 00000000
          //  (0x76543210): 00000000 00000000 00000000 00000000
          //  (0x76543220): 00000000 00000000 00000000 00000000
          

          在此示例中,我将您的 *p=0; 更改为 *p=5;,以便我们可以看到内存的变化。所以现在假设我们运行这些代码行:

          int *p;                // Declare a pointer p
          p = (int*) 0x76543210; // Set p to point at the address 0x76543210 cast to (int*)
          *p = 5;                // Go to the address that p is pointing to, and set the value to 5
          

          现在如果我们回过头来看看我们的记忆,我们应该看到我们将 5 设置为 p 指向的地址:

          //  Dummy Memory Dump
          //   Offset:      0        4        8        C
          //  (0x76543200): 00000000 00000000 00000000 00000000
          //  (0x76543210): 00000005 00000000 00000000 00000000
          //  (0x76543220): 00000000 00000000 00000000 00000000
          

          说明

          通常,声明分为以下几部分:

          [type] [name];
          

          并且可选地,可以像这样破坏内联初始化:

          [type] [name] = [value];
          

          在这个例子中:

          int *p=5;
          
          • [类型] = (int*)
          • [名称] = p
          • [值] = 5

          这可能会造成混淆,因为声明中的 * 附加在名称上。声明中的 * 仅表示 p 是一个指针。 但是指针的名字还是只是p。

          既然我们知道了组件,我们就可以这么说

          int *p=5;
          

          等价于

          int *p;
          p=5;
          

          现在更令人困惑的是,声明指针时的 * 和访问指针地址时的 * 是有区别的。 在访问时使用 * 时,它使用 p 中的值作为将要访问的地址。 在这个例子中:

          int *p; // This declares a pointer p with no value
          *p=5;   // This line wants to go to the address that p is pointing to and set it to 5
                  // At this point, p is undefined because p was just declared and hasn't been set
                  // So it is trying to go to an unknown location to set the value 5.
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-12-30
            • 2016-01-23
            • 2021-01-05
            • 2019-08-14
            • 2013-08-14
            • 1970-01-01
            • 1970-01-01
            • 2019-12-14
            相关资源
            最近更新 更多