C 正确的阅读方法';int*ptr=&;x';

C 正确的阅读方法';int*ptr=&;x';,c,pointers,initialization,declaration,C,Pointers,Initialization,Declaration,下面的代码很容易解释为 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的地址分配给指向的值

下面的代码很容易解释为

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*
是类型,因此它非常有意义。只是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;
这将产生一个完全不同的警告,因为您正在将一个变量的地址分配给类型为
int
pb的变量

int *pa = &x, pb = &x;
但是,使用上面的typedef,您可以(但可能不应该)执行以下操作:

但有一种方式可以认为,在任何情况下取消对未初始化指针的引用都毫无意义

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

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

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

因为,如果同时声明几个指针,那么忘记星号会容易得多。这给人的印象是
int*p,q声明两个指针

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

int (*p)[3]
int *p[3]
const int *p[3]
int *const p[3]
const int (*p)[3]
int (*const p)[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;
}
请注意,在C语言中,正如在许多其他语言中一样,一些符号是重载的,它们的含义取决于上下文。例如,符号<代码>和<代码>可以表示操作符和位和操作符的地址,并且在C++中,这个符号也可以表示引用。

< P>比较下面的内容。
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

诚然,这是C语言中一个奇怪的部分,主要是由于C语言的进化

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

(初始化可以“分配”到静态/文件范围变量,这样的分配不会生成代码:它只是对生成的二进制文件的组成起作用。除非优化可以删除它,否则分配始终会生成代码)

在史前的C语言中,初始化和赋值的外观非常不同,在史前C语言中,初始化时不使用
=
符号,如
intx42。(即使在初始化语法中添加了
=
之后,也很难初始化本地、非静态变量,这意味着
int*p=&x;
等情况并不经常出现。)

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


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

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

非常简单,类型是
int*
,无论距离
int
*
有多远。你甚至可以写
int*ptr=x这仍然是有效的。正确阅读只是习惯问题
*p1 = 10
*p2 = 10
*p3 = 10
*p4 = 10
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