多级指针
前言
我们如何用一个指针对象去指向另一个指针对象的地址呢?此时,我们将引入多级指针这一概念。
如果我们要指向一个一级指针的地址,比如 int*p,此时如果要指向p的地址------&p,那么我们需要一个二级指针对象。比如:int **q=&p。这里q就是指向一级指针p的一个二级指针,其类型为int **,表示指向一个指针的指针。
我们通过代码清单观察二级指针、一级指针以及普通对象之间的关系。
c
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
int main() {
int32_t x=10,y=20;
int32_t *p=&x, *q=&y;
int32_t **pp=&p;
bool b = *pp == &x
printf("b = %d'n", b);
**pp = q;
printf("p == q ? %d'n", p==q);
**pp = 30; //这一步把y的值改为30
printf("y = %d\n", y);
}
指向用户自定义类型的指针
指针除了可以指向整数,还可以定义指向枚举、结构体以及联合体类型的指针。指向枚举类型的指针与一般指向基本类型的指针差不多,只不过类型变为枚举类型。对于一个普通结构体对象要访问成员时,使用"."操作符,而当用指针访问时,必须使用"->"成员访问操作符。
下面举个例子
c
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 枚举
enum TRAFFIC_LIGHT{
TRAFFIC_LIGHT_RED,
TRAFFIC_LIGHT_YELLOW,
TRAFFIC_LIGHT_GREEN,
} light, *pe = &light;
enum TRAFFIC_LIGHT *pe2 = pe;
*pe2 = TRAFFIC_LIGHT_YELLOW;
pritnf("light=%d'n", light);
struct S {
int a;
enum TRAFFIC_LIGHT *pe;
} s, *p = &s; // 直接声明一个对象s以及指向该结构体类型的指针对象p
p->a = 10;
p->f = -0.5f
p->pe = &light;
//也可以用下列方式访问成员,但注意要加上括号
(*p).a = 10;
}
指针与数组的关系
接下来我们介绍C语言中数组和指针的关系、本质以及指针运算规则。
- 数组与指针是不同类型
- 数组属于聚合类型
- 指针属于标量类型
虽然不同,但数组在表达式中通常会自动退化位指针。
例如
c
int a[5]; //会自动转换为int *
// 即指向数组首元素a[0]的地址
但以下情况不会退化
- sizeof(a)
- &_Alignof
- &a
数组名本质上常被当作首元素指针使用
c
a[1]
// 等价于下面
*(a+1)
`` 说明:
- 下标访问实际上是指针+偏移量
- 再通过*解引用得到元素
- 指针不是普通整数加法
c
type *p;
// 则
p+1 // 等价于地址 + sizeof(type),即跳到下一个同类型元素
int *p
// p+1 地址实际上增加 4 字节
总结:
- 数组和指针关系非常紧密
- 数组名多数情况下就是首元素地址
3) 下标访问本质是地址偏移计算
4)C语言底层非常接近内存模型与硬件操作