二级指针与取地址运算符

本文详细解析了C语言中二级指针的概念,包括指针的定义、本质、指针变量的地址和数据类型,以及如何通过二级指针访问底层变量,通过实例演示了二级指针的应用。
 

    接下来,我们结合下面的例子来理解二级指针的概念。

#include <stdio.h>

int main(void)
{
    int a = 3;

    int *one_ptr = &a; //相当于int *one_ptr;one_ptr = &a;

    int **two_ptr = &one_ptr; //相当于int **two_ptr; two_ptr = &one_ptr;

    printf("&a = %p, one_ptr = %p, *two_ptr = %p\n", &a, one_ptr, *two_ptr);
    printf("&one_ptr = %p, *two_ptr = %p\n", &one_ptr, two_ptr);
    printf("a = %d, *one_ptr = %d, **two_ptr = %d\n", a, *one_ptr, **two_ptr);

    return 0;
}

     1、指针的定义和本质

    如例子中的第7行,它的意思是声明一个指针变量one_ptr并给此指针变量赋值整型变量a的地址值。

    注意:(1)其中的星号(*)仅仅用来表示变量one_ptr是一个指针变量(一定要特别注意,one_ptr才是指针变量,而不是*one_ptr);(2)星号(*)在C语言中有三种用法,乘法运算符、间接运算符和在声明中用来表示指针,后两种的用法都与指针有关;(3)这里的数据类型关键字int与指针变量本身没有任何关系(指针变量本身也是有数据类型的,但在C语言中它没有相关的关键字来表示,我们只知道在32位的机器中指针变量通常是4个字节的,用来存储一个32位的字节地址),仅表示指针变量one_ptr只能用来存储某个整型数据(如a)的首地址,否则会警告类型不匹配。

    同理,例子中的第9行,它的意思是声明了一个指针变量two_ptr并给此指针变量赋值像int *这样的数据类型变量(如one_ptr)的首地址。

    总结来说,在一个指针变量声明中,靠近指针变量名字的星号(*)是星号的第三种用法,其他部分都是所声明的这个指针变量将要指向的变量的数据类型。如指针变量one_ptr将要指向的变量的数据类型为int型,指针变量two_ptr将要指向的变量的数据类型为int *型。也就是说int 和*共同决定了变量one_ptr的所有特性并有两层含义,星号(*)表示变量one_ptr是指针变量,关键字int表示这个指针变量one_ptr将要指向的变量的数据类型为整型,类似的道理,int *和*共同决定着变量two_ptr的所有特性。

    2、指针变量的地址和值

    在C语言中,任何类型的变量都有两个基本属性:地址和数值。地址也是一个数值,在32位的机器中,地址就是一个32位的无符号整型数。一般通过取地址运算符(&)来获取一个变量的地址值。

    如例子中,变量a的数值为3,地址为&a;变量one_ptr的值为&a,地址为&one_ptr;指针变量two_ptr的值为&one_ptr,地址为&two_ptr(例子中并没有打印出这个值)。

    例子结果输出:

&a = 0xbfac7f28, one_ptr = 0xbfac7f28, *two_ptr = 0xbfac7f28
&one_ptr = 0xbfac7f24, *two_ptr = 0xbfac7f24
a = 3, *one_ptr = 3, **two_ptr = 3

    *one_ptr和**two_ptr都相当于在使用整型变量a,*two_ptr就相当于在使用指针变量one_ptr。

    思考:指针变量的数据类型是什么?

<think> 我们讨论的是C语言中的两个运算符:指针运算符(解引用运算符,用符号`*`表示)和取地址运算符(用符号`&`表示)。这两个运算符都是一元运算符,即它们只需要一个操作数。 根据提供的引用(特别是引用[4]),我们可以找到运算符的优先级表。在表中,一元运算符(包括`*`和`&`)属于第二优先级(在表中标注为“2”),并且它们的结合性是从右到左。 具体来说: - 指针运算符`*`:用于解引用指针,获取指针所指向的内存地址中的值。 - 取地址运算符`&`:用于获取变量的内存地址。 在优先级表中,一元运算符(如`*`和`&`)具有相同的优先级,并且高于大多数其他运算符(除了后缀运算符和类型转换运算符等)。因此,在表达式中,一元运算符`*`和`&`会先于乘法运算符`*`(注意乘法运算符是二元运算符,优先级较低)等运算。 例如,考虑以下表达式: ```c int a = 10; int *ptr = &a; int b = *ptr + 5; // *ptr先计算,然后再加5 ``` 这里,`*ptr`中的`*`是一元运算符,它先于加法运算符`+`计算。同样,`&a`也是一元运算符,在赋值给`ptr`时,它先计算。 另一个例子,如果同时出现两个一元运算符,由于一元运算符的结合性是从右到左,所以会从右向左计算。例如: ```c int x = 10; int *ptr = &x; int y = *&x; // 相当于*(&x),先取地址再解引用,结果还是x的值 ``` 在这个例子中,先执行`&x`得到x的地址,然后执行`*`得到该地址的值,即x的值。 再考虑一个更复杂的表达式,包含一元运算符和其他运算符: ```c int a = 10; int *ptr = &a; int b = *ptr * 2; // 这里*ptr先计算(解引用),然后乘以2 ``` 这里,第一个`*`是指针运算符(一元),第二个`*`是乘法运算符(二元)。由于一元运算符优先级高于乘法运算符,所以先计算`*ptr`,然后再乘以2。 因此,总结如下: - 指针运算符(`*`)和取地址运算符(`&`)都属于一元运算符,优先级为第二级(较高),结合性为从右到左。 - 在表达式中,它们会先于大部分二元运算符(如算术运算符、关系运算符等)进行计算。 如果表达式中有多个一元运算符连续出现(如`*&*p`),则按照从右向左的顺序结合。 引用[4]中的优先级表明确列出了: ``` 2 一元运算符:++ -- ! ~ + - * & sizeof _Alignof 从右到左 ``` 其中就包括`*`(解引用)和`&`(取地址)。 因此,回答用户的问题:指针运算符`*`和取地址运算符`&`在C语言中具有相同的优先级(属于一元运算符,优先级为第二级),并且结合性是从右到左。 </think>### C语言指针运算符取地址运算符的优先级详解 在C语言中,指针运算符`*`(解引用运算符)和取地址运算符`&`都属于**一元运算符**,具有**相同的优先级**(第二高优先级),且结合性为**从右向左**。以下是详细分析: #### 1. **优先级层级** 根据C语言标准(参考引用[1][4]): | 优先级 | 运算符类别 | 包含运算符 | 结合性 | |--------|------------|------------|--------| | 1 | 后缀运算符 | `[]` `()` `->` `.` | 左→右 | | **2** | **一元运算符** | **`*`(解引用) `&`(取地址) `++` `--` `+`(正号) `-`(负号)** | **右→左** | | 3 | 类型转换 | `(type)` | 右→左 | | 4 | 乘除类 | `*` `/` `%` | 左→右 | #### 2. **具体分析** 1. **相同优先级**: - `*`和`&`同属第二优先级,优先级高于算术运算符(如`+`、`-`)、关系运算符(如`<`、`==`)等 - 示例:`int x = *&a + 5;` 等价于`int x = (*(&a)) + 5;` 先计算`&a`(取地址),再`*`解引用,最后`+5`[^4] 2. **结合性(从右向左)**: - 表达式`*&var`:先计算`&var`(取地址),再`*`解引用 - 表达式`&*ptr`:先计算`*ptr`(解引用),再`&`取地址(可能无效) - 示例:`int y = *&*&b;` 等价于`int y = *( &( *( &b ) ) );`[^4] #### 3. **典型使用场景** ```c #include <stdio.h> int main() { int num = 10; int *ptr = &num; // &优先级高于=,先取地址再赋值 printf("值: %d\n", *&num); // 输出10 (*和&优先级相同,右→左结合) int **pptr = &ptr; // &&错误!&ptr是二级指针 printf("二级指针值: %d\n", **pptr); return 0; } ``` #### 4. **易错点** 1. **无效操作**: ```c int a = 10; int *p = &*a; // 错误!a不是指针,*a无效 ``` 2. **混淆二元`*`**: ```c int x = 5, y = 10; int z = *&x * y; // 正确:等价于 x * y int w = &x * y; // 错误!&x是地址,不能相乘 ``` #### 5. **最佳实践** - **明确分组**:复杂表达式使用`()`显式指定优先级 `int value = *(ptr + offset);` 比 `int value = *ptr + offset;`更安全 - **避免连续一元操作**:`*&var`可直接写为`var` - **类型检查**:`&`只能用于左值,`*`只能用于指针[^1][^4] > 💡 **关键记忆点**: > `*`和`&`优先级相同(高于乘除),结合方向从右向左, > 连续使用时先执行最右侧操作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tanglinux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值