【问题标题】:Proper way to read 'int * ptr=&x'阅读“int * ptr=&x”的正确方法
【发布时间】:2021-05-23 12:33:32
【问题描述】:

下面的代码很容易解释为

int x=4;
int *ptr;  // ptr is a pointer to an int
ptr=&x; // the address of x  is assigned to the pointer ptr

但下面的等效代码可能会让人误解

int *ptr=&x; //  the address of x is assigned to  *ptr, which is an integer

那似乎被解释为将 x 的地址分配给指向的值 *ptr (int *ptr )= &x 声明和初始化分开时的正确解释应该写成int *(ptr = &x),以表明赋值是指向指针而不是指向位置,但这会产生错误,为什么会这样?阅读和思考int *ptr=&x 的最佳方式是什么?

【问题讨论】:

  • 很简单,类型是int *,不管int*的距离。你甚至可以写int * ptr=x;,这仍然有效。正确阅读只是习惯问题。
  • @Marco Bonelli 我看到了,但我通常发现它写为 int *ptr ,即指针名称旁边的 * ,这没有帮助。可以解释为int(*ptr),说ptr指向的值是整数是正确的

标签: c pointers initialization declaration


【解决方案1】:

当声明一个指针时,int p 等于 int p; int* 是一种类型。

【讨论】:

    【解决方案2】:

    这无疑是 C 的一个奇怪部分,主要是由于 C 的演变。

    在 C 的语法中,声明旨在镜像使用,因此在 int *x; 之后,*x 解析为 int*x=42 分配给 int。但是在声明的specifiers declarator 部分之后以= 开头的初始化在语法和语义上与赋值不同。

    (初始化可以“分配”给静态/文件范围变量,这样的分配不会生成代码:它只是对生成的二进制文件有贡献。分配总是会生成代码,除非优化可以删除它)

    在史前 C 中,初始化和赋值过去看起来非常不同,在这种情况下,您可以在没有 = 符号的情况下进行初始化,就像在 int x 42; 中一样。 (即使在 = 被添加到初始化的语法中之后,长期以来也无法初始化局部的、非静态的变量,这意味着像 int *p = &x; 这样的情况并不经常出现。)

    旧的语法有问题(int x (42); 也会声明和初始化x 还是函数声明?)这就是它被替换的原因,但我喜欢它强调初始化与赋值不同的方式。

    不幸的是,使用新语法(如int x, *p = &x;),这种区别并不那么明显,您只需要记住,当您在左端有类型说明符(int)时,那么=并不表示您可以只查看*p = &x 的赋值,而是表示它是一个初始化,您必须查看整个声明并查看声明的内容(x 作为intp 作为指向 int) 的指针。然后,该上下文中的 = 会初始化声明的标识符。

    【讨论】:

    • 感谢这非常有助于了解为什么一些看起来像赋值的表达式不是赋值。我不知道我是否应该在这里使用“表达”这个词,但是,另一种奇怪的技术性说明
    【解决方案3】:

    你可以写

    int ( *ptr ) = &x;
    

    甚至喜欢

    int ( * ( ptr ) ) = &x;
    

    虽然这个记录

    int *ptr = &x;
    

    对于每个 C 程序员来说都很清楚,因为它是一个声明,而不是一个赋值语句。此外,在 C 中,与 C++ 声明相反的不是语句。

    即 1) 您不能将声明括在括号中,就像您写的 (int *ptr )= &x 和 2) 您可以将声明符括在括号中。

    如果按照你的逻辑,那么你应该像这样写声明

    int *p = ( p = &x );
    

    这使声明更加混乱。:)

    这是一个演示程序,展示了一些声明和初始化指针的示例。

    #include <stdio.h>
    
    int main(void) 
    {
        int x = 10;
        
        int *p1 = &x;
        int ( *p2 ) = &x;
        int ( *( p3 ) ) = &x;
        
        int typedef *T;
        
        T ( p4 ) = &x;
        
        printf( "*p1 = %d\n", *p1 );
        printf( "*p2 = %d\n", *p2 );
        printf( "*p3 = %d\n", *p3 );
        printf( "*p4 = %d\n", *p4 );
    
        return 0;
    }
    

    程序输出是

    *p1 = 10
    *p2 = 10
    *p3 = 10
    *p4 = 10
    

    请注意,在 C 中,与在许多其他语言中一样,一些符号被重载,它们的含义取决于上下文。例如符号&amp;可以表示运算符的地址和按位与运算符,顺便说一下,在C++中这个符号也可以表示一个引用。

    【讨论】:

    • "int *ptr = &x 对于每个 C 程序员来说都很清楚,因为它是一个声明而不是赋值语句。"这不是一个声明加上一行中的赋值吗?我的意思是它是一个声明加上一个初始化,而初始化是一个值的分配
    • @J.C.VegaO 有一行包含声明。初始化不是赋值语句。
    • 对不起,我不明白为什么初始化不是赋值,当我做int x; x=4;时,第二条语句使用赋值运算符=初始化变量
    • @J.C.VegaO 初始化基本上是在声明期间完成的赋值。但也有一些特殊情况。在某些情况下,您必须使用初始化,而在某些情况下,您不能这样做。
    • @J.C.VegaO 如果将初始化视为 C 标准中定义的严格术语,则初始化不是赋值。我们现在在 C 标准的背景下发言。在更一般的上下文中,术语初始化用于表示对变量的任何赋值。
    【解决方案4】:

    int * 是类型,所以它非常有意义。只是 C 中的指针表示法可能需要一些努力才能习惯。但是看看这段代码

    typedef int* int_ptr;
    int x;
    int_ptr ptr = &x;
    

    同样的事情。但是,通常建议不要 typedef 指针。

    混淆来自* 有两个角色。命名类型和取消引用指针都是如此。第一个例子是sizeof(int*)

    如果你同时声明多个指针,它看起来更混乱,但它仍然是一样的。一般来说,建议不要一次声明多个指针。因为如果我们想用两个指针来做上面的事情,它看起来像这样:

    int *pa = &x, *pb = &x;
    

    和这个是一样的

    int *pa = &x;
    int *pb = &x;
    

    这会做一些完全不同的事情,并且会产生警告,因为您将变量的地址分配给 pb 类型为 int 的变量

    int *pa = &x, pb = &x;
    

    但是,使用上面的 typedef,您可以(但可能不应该)这样做:

    int_ptr pa=&x, pb = &x;
    

    但一种思考方式是,在任何情况下取消引用未初始化的指针都是没有意义的。

    阅读和思考int *ptr=&amp;x 的最佳方式是什么?

    请注意,取消引用未初始化的指针是没有意义的。而且您正在对指针进行初始化,因此您应该使用(有效)地址对其进行初始化。

    好的,我明白了,另一件事。如果类型是int*,为什么它几乎总是像*那样写在指针变量旁边,而不是像int *ptr?,即使像@987654336一样写它也会更有意义@。

    因为,如果一次声明多个指针,那么忘记星号会容易得多。这会让人觉得int* p,q; 声明了两个指针。

    C 指针语法很笨拙。这是一种非常古老的语言。习惯就好。它永远不会改变。只是为了好玩,这里有一个页面可以告诉https://cdecl.org/ 是什么声明,所以试试这些:

    int (*p)[3]
    int *p[3]
    const int *p[3]
    int *const p[3]
    const int (*p)[3]
    int (*const p)[3]
    

    【讨论】:

    • 对于像int *px = &amp;x, *py = &amp;y;这样的行变得更加棘手。
    • 哦,我以前认为 int *ptr 为 int (*ptr),即取消引用声明中的指针,因为说地址 ptr 的内容是有道理的,即 *ptr是一个整数。这样看是不是错了?
    • @AdrianMole 真的。修好了。
    • @J.C.VegaO 嗯,我该怎么形容呢?你说的有道理,但是错了。看看我的最后一段。取消引用未初始化的指针是没有意义的。
    • 好吧,我明白了,另一件事。如果类型是 int*,为什么它几乎总是像指针变量旁边的* 那样写,而不是像int *ptr?,它会更有意义,即使写成int* ptr
    【解决方案5】:

    比较以下。

    int n = 5;     // (a) defines 'int' variable 'n' and initializes it to '5'
    
    int *p;        // (b) defines 'int*' pointer variable 'p`
    p = &n;        //     initializes 'p' to '&n'
    
    int *p1 = p;   // (c) defines 'int*' pointer variable 'p1' and initializes it to 'p' 
                   //     syntactically, it looks just like (a), but for a pointer type
    
    int *p2 = &n;  // (d) same as (b) and (c) combined into a one-liner
    
    int n3 = 7, *p3 = &n3;  // (e) same as (a), (b) and (c) combined into a one-liner
    

    【讨论】:

      猜你喜欢
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2016-12-17
      • 2018-02-12
      • 2019-10-23
      • 1970-01-01
      • 2020-08-03
      相关资源
      最近更新 更多