c之指针解引用运算符之语法规则
我不确定是否正确使用了星号运算符。请考虑以下示例:
#include<stdio.h>
int main() {
char *w[3]; //Array of pointers
w[0] = "Apple";
w[1] = "Pear";
w[2] = "Peach";
printf("w[0] = %s, w[1] = %s, w[2] = %s\n", w[0], w[1], w[2]);
char **p = &w[0];
char ***q = &p;
printf("&w[0] = %p, *p = %s, p = %p, q = %p, *q = %p, **q = %s\n",
&w[0], *p, p, q, *q, **q);
return 0;
}
我对使用指针的期望:
int n = 3;
int *a = &n; -> a = &n -> *a = 3
int **b = &a; -> b = &a -> *b = &n -> **b = 3
int ***c = &b; -> c = &b -> *c = &a -> **c = &n -> ***c = 3
以上,
p
是一个指向指针的指针。
p
持有地址
&w[0]
和
*p
返回
&w[0]
内部的值.不应该用
**p = "Apple
来完成?
同理,不应该是
***q = "Apple
, 而不是
**q
?
我没有找到一个资源来让我非常清楚指针到 Npointers 运算符的正确使用。从这个意义上说,任何建议都将受到高度赞赏。我希望我能够充分表达我的问题。
请您参考如下方法:
现在我将尝试对指针进行一些澄清,为了易于理解,我现在将以简化的方式公开这些内容。
C 中的指针是一个变量,与其他任何类型一样,它的类型是内存中的地址。
不幸的是,只有一个指向进程内存中某处的地址不足以正确交互,而不会损坏与指针指向的位置相邻的其他实体(通常是变量)。为此,该语言提供了 资质允许用户指定它指向哪个对象(类型),并允许编译器选择它使用的方式来访问符合所指向对象的内存。
说了这个,回到你最初的问题,现在应该清楚指针是一个变量,它可以保存 C 语言中存在的任何类型的地址,基本的或派生的。
现在我们进入正式部分。为了与指针交互,我们需要一些运算符来处理它们,基本上是一个解析为变量地址的运算符,一个解析为 的运算符。值 从指针和声明运算符到 的变量“声明”一个指针。
让我们从开始取消引用运算符 *
.该运营商返还 值 (取消引用)对象从指向它的指针。但它也是声明者 为一个指针,因为是最多的 自然视觉呈现 的一个指针。看看下面的声明:
int * p_int;
阅读 C 风格的声明,从右到左,我们可以说:
p_int
is a variable that dreferenced give the value of anint
.
这是一个 指针 .
现在,如果我们已经声明了一个变量
p_int
是指向
int
类型的对象的指针当我们取消引用它时,编译器知道要给我们一个
int
value 它必须访问从指针指向的位置开始的内存字节并打包一些字节,这是为
int
请求的。在我们正在使用的机器/编译器上,一起形成一个
int
.
无论如何,指针与任何其他变量一样,必须被初始化或分配以包含有效地址,然后才能用于某些事情。所以我们必须为我们的指针初始化/分配一个值,该值必须与它指向的对象类型兼容。如果我们有一个变量:
int an_int;
兼容类型它可以适合范围。但是指针保存着对象的地址,所以我们不能直接赋值:
p_int = an_int; //The compiler will trigger an error for incompatible type
要分配它,我们必须获得变量在内存中的地址。我们需要一元运算符
&
返回应用它的对象的地址。
p_int = &an_int; //we assign to p_int the address in memory of an_int
当然,我们可以通过取消引用来再次访问存储在我们的指针指向的地址处的值:
int another_int = *p_int;
在结束之前我们必须说一种 《特殊处理》 C语言为 预留的数组 .在 C 数组的名称会自动转换为其第一个元素的地址 (接下来我们将看到标准中对此存在哪些限制)。这意味着数组声明后的 2 行是等效的:
int array_of_int[10];
int *p_int = array_of_int;
int *p_int1 = &array_of_int[0];
(即使
int *p_int1 = &array_of_int;
也是等价的,原因我们将在下面看到)。
现在我们考虑你的例子。声明:
char *w[3];
char **p = &w[0];
char ***q = &p;
必须读作 “
w
是一个由 3 个指向 char 的指针组成的数组,p
是一个指向 int
的指针,q
是一个指向 int
的指针的指针。” .
让我们解码。数组的每个元素
w
持有
char
的地址, 如果内存中有
char
的数组从那个地址开始,对于我们之前说的关于数组的传递性质,我们可以说每个
w
element 保存第一个
char
的地址共 3
char
未指定维度的数组。当然,这些数组中的每一个都包含 3 个单词“Apple”、“Pear”和“Peach”。在声明中:
char **p = &w[0];
我们在内存中创建了一个保存地址的变量,其中保存了指向
char
的指针的值。存储在数组的第 0 个元素中
w
.考虑一下
w[0]
将给出字符串“Apple”开始的地址,而不是保存字符串“Apple”开始的地址的第 0 个元素的地址(重复,但必须清楚!)。所以我们使用一元运算符
&
获得这样的地址。
真正有趣的一点是声明中的 2 个星号是声明性的,而不是运算符本身。澄清考虑:
char **p;
p = &w[0];
这完全等同于前一行,但在第一行我们声明了一个指向
char
的指针。 ,在第二个我们分配它
w
的第一个元素的地址.
这应该足以解释问题的其他部分。
现在让我们更正式地看看 C 标准。我们已经说过,在某些情况下,数组和指针是由编译器自动转换的。这是在 中准时说明的ISO/IEC 9899:2011 § 6.3.2.1“左值、数组和函数指示符”第 3 小节 :
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
这也解释了因为使用
&
数组操作数上的运算符无论如何都会解析为第一个数组对象的地址。
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。