五:多级指针与指针数组,带你深入了解指针

1. 指针的指针

在C语言中,指针用于存储变量的地址。如果我们另一个指针去指向这个指针的地址,这样的指针叫做“指针的指针”。我们可以对指针进行取地址运算,看看是否能编译通过。

```
#include <stdio.h>

int main() {
    int n = 123;
    int *pn = &n;         // pn 是指向 n 的指针
    printf("pn = %u\n", pn);       // 打印 pn 的值,指向 n 的地址
    printf("&pn = %u\n", &pn);     // 打印 pn 的地址
    return 0;
}
```

如上代码可以成功编译并运行。`pn` 是一个指针,指向变量 `n`,而 `&pn` 是 `pn` 的地址,类型是指向指针的指针。

2. 指针的类型

指针的指针应该是什么类型呢?通过在原指针类型前再加一个星号,我们可以得出结论:

```
int **p;  // p 是指向 int * 类型的指针
```

需要注意,指针变量的声明中,类型和变量名之间的空格并不是严格的,比如以下声明都是正确的:

```
int *p;    // 正确
int*p;     // 正确
int* p;    // 正确
int **p;   // 正确(对于指针的指针)
```

因此,`int **p` 表示 `p` 是一个指向 `int *` 类型的指针。

3. 多级指针

`int **` 是指向 `int *` 类型数据的指针,称为二级指针。我们可以用取值运算符 `*` 来访问指针指向的值。

```
#include <stdio.h>

int main() {
    int n = 123;
    int *pn = &n;         // pn 是指向 n 的指针
    int **pnn = &pn;     // pnn 是指向 pn 的指针
    printf("**pnn = %d\n", **pnn); // 获取 pnn 指向的值,即 n 的值
    return 0;
}
```

深入理解:

取地址的过程如下:
- 对 `n` 使用取地址运算符,得到 `pn`,类型为 `int *`。
- 对 `pn` 使用取地址运算符,得到 `pnn`,类型为 `int **`。
   
取值过程:
- 对 `*pnn` 使用取值运算符,将其还原为 `int *`。
- 再对 `*(*pnn)` 使用取值运算符,还原为 `int`,即变量 `n` 的值。

为了展示多级指针的概念,可以这样扩展:

```
#include <stdio.h>

int main() {
    int n = 123;
    int *oneStar = &n;         // int *
    int **twoStar = &oneStar;  // int **
    int ***threeStar = &twoStar; // int ***
    // 继续扩展更多级
    printf("n = %d\n", *****fiveStar); // 多次解引用
    return 0;
}
```

4. 指针数组

指针数组是一个元素为指针的数组。先来看一个整型数组的例子:

```
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {11, 22, 33, 44, 55};
int arr3[5] = {111, 222, 333, 444, 555};
```

这些常规数组的名称会被转换为指向其首元素的指针。我们定义一个指针数组来存储这些指针:

```
int *pToArr[3];
pToArr[0] = arr1; // arr1转换为首元素指针
pToArr[1] = arr2; // arr2转换为首元素指针
pToArr[2] = arr3; // arr3转换为首元素指针
```

在这个例子中,`pToArr` 是一个指针数组,类型为 `int *[3]`,包含三个 `int *` 类型的元素,分别指向 `arr1`、`arr2` 和 `arr3`。

遍历指针数组

你可以使用嵌套循环来遍历指针数组中的所有元素:

```
for(int i = 0; i < 3; i++) {
    int *p = pToArr[i]; // 指向第 i 个数组的首元素
    for(int j = 0; j < 5; j++) {
        printf("%d ", *(p + j)); // 打印元素值
    }
    printf("\n");
}
```

5. 从函数中返回指针

我们可以让函数返回一个指针。示例代码如下:

```
#include <stdio.h>

int* func() {
    int n = 100; // 局部变量
    return &n;   // 返回指向局部变量 n 的指针
}

int main() {
    int* p = func(); // p 现在指向 func 内部的 n
    printf("%d\n", *p); // 潜在问题:访问失效的内存
    return 0;
}
```

这个例子看似没问题,但因为变量 `n` 在函数 `func` 执行完毕后被回收,我们无法安全地访问它。

解决方法:

我们可以使用 `static` 关键字,让变量在函数执行完毕后不会被回收:

```
int* func() {
    static int n = 100; // n 不会被回收
    n++; // 每次调用时自增
    return &n; // 返回 n 的地址
}
```

这样,在每次调用 `func` 后,变量 `n` 会保持其状态并自增。

 6. 从函数中返回多个变量

要从函数返回多个值,可以将指针作为参数传递。示例代码如下:

```
#include <stdio.h>

void func(int **a, int **b) {
    static int x = 100;
    static int y = 200;
    *a = &x; // 将 x 的地址赋给指针
    *b = &y; // 将 y 的地址赋给指针
}

int main() {
    int *a = NULL;
    int *b = NULL;
    func(&a, &b); // 将指针的指针传入
    if (a != NULL && b != NULL) {
        printf("a=%d b=%d\n", *a, *b); // 打印 x 和 y 的值
    }
    return 0;
}
```

在这个代码中,我们通过函数 `func` 来修改主调函数中的指针 `a` 和 `b`。

总之,使用指针,可以有效地管理和共享变量的地址,使函数之间的变量传递更为灵活。希望这些示例能帮你进一步理解多级指针与指针数组的概念。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值