正确的阅读方式 'int * ptr=&x'
Proper way to read 'int * ptr=&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 pa=&x, pb = &x;
但一种思考方式是,在任何情况下取消引用未初始化的指针都毫无意义。
And what is the best way to read and think of int *ptr=&x
?
假设取消引用未初始化的指针是没有意义的。您正在对指针进行初始化,因此您应该使用(有效)地址对其进行初始化。
Ok, I see that, another thing. If the type is int*
why is it almost always written like with the *
next to the pointer variable instead, like int *ptr
?, it would make more sense, even if it is the same to write it like int* ptr
.
因为,如果一次声明多个指针,那么忘记星号会容易得多。这会给人一种印象,即 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 ( *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 中,与在许多其他语言中一样,一些符号被重载,它们的含义取决于上下文。例如,符号 &
可以表示运算符的地址和按位与运算符,顺便说一句,在 C++ 中,这个符号也可以表示引用。
比较以下。
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
.但是在声明的 specifiers declarator
部分之后以 =
开始的初始化在句法和语义上与赋值不同。
(初始化可以“赋值”给 static/filescope 变量,这样的赋值不会生成代码:它只是有助于生成二进制文件的构成。赋值总是生成代码,除非优化可以删除它)
在史前 C 语言中,初始化和赋值看起来非常不同,在 C 语言中,您可以在没有 =
符号的情况下进行初始化,就像在 int x 42;
中一样。 (即使在 =
被添加到初始化语法之后,很长时间以来都不可能初始化局部的、非静态的变量,这意味着像 int *p = &x;
这样的情况并不经常出现。)
旧语法有问题(int x (42);
也会声明和初始化 x
还是函数声明?)这就是它被替换的原因,但我喜欢它强调初始化的方式与作业不同。
不幸的是,在新语法中(如 int x, *p = &x;
),这种区别并不那么明显,您只需要记住,当您在左端有类型说明符 (int
) 时,那么 =
并不表示您只能查看 *p = &x
的赋值,而是表示您必须查看整个声明的 初始化 和查看声明的内容(x
作为 int
和 p
作为指向 int
的指针)。该上下文中的 =
然后初始化声明的标识符。
当声明一个指针时,int p 等于 int p; int* 是一种类型。
下面的代码很容易理解为
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 pa=&x, pb = &x;
但一种思考方式是,在任何情况下取消引用未初始化的指针都毫无意义。
And what is the best way to read and think of
int *ptr=&x
?
假设取消引用未初始化的指针是没有意义的。您正在对指针进行初始化,因此您应该使用(有效)地址对其进行初始化。
Ok, I see that, another thing. If the type is
int*
why is it almost always written like with the*
next to the pointer variable instead, likeint *ptr
?, it would make more sense, even if it is the same to write it likeint* ptr
.
因为,如果一次声明多个指针,那么忘记星号会容易得多。这会给人一种印象,即 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 ( *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 中,与在许多其他语言中一样,一些符号被重载,它们的含义取决于上下文。例如,符号 &
可以表示运算符的地址和按位与运算符,顺便说一句,在 C++ 中,这个符号也可以表示引用。
比较以下。
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
.但是在声明的 specifiers declarator
部分之后以 =
开始的初始化在句法和语义上与赋值不同。
(初始化可以“赋值”给 static/filescope 变量,这样的赋值不会生成代码:它只是有助于生成二进制文件的构成。赋值总是生成代码,除非优化可以删除它)
在史前 C 语言中,初始化和赋值看起来非常不同,在 C 语言中,您可以在没有 =
符号的情况下进行初始化,就像在 int x 42;
中一样。 (即使在 =
被添加到初始化语法之后,很长时间以来都不可能初始化局部的、非静态的变量,这意味着像 int *p = &x;
这样的情况并不经常出现。)
旧语法有问题(int x (42);
也会声明和初始化 x
还是函数声明?)这就是它被替换的原因,但我喜欢它强调初始化的方式与作业不同。
不幸的是,在新语法中(如 int x, *p = &x;
),这种区别并不那么明显,您只需要记住,当您在左端有类型说明符 (int
) 时,那么 =
并不表示您只能查看 *p = &x
的赋值,而是表示您必须查看整个声明的 初始化 和查看声明的内容(x
作为 int
和 p
作为指向 int
的指针)。该上下文中的 =
然后初始化声明的标识符。
当声明一个指针时,int p 等于 int p; int* 是一种类型。