三:指针在数组中的应用

1. 使用指针访问数组

指针的加减运算可以用来在内存中移动指针的地址。加上一个整数 `n`,实际上就是移动了 `n` 个步长字节。步长是由指针指向的数据类型决定的。

例如,假设有一个 `int` 类型的指针 `p`:

int *p = (int *)100;


那么,执行 `p + 1` 后,指针地址会向后移动 `sizeof(int)` 字节(通常是4字节),即地址变为104。同样,执行 `p - 1` 后,指针地址会向前移动4字节,变为96。

这种加减运算对于访问在内存中连续排布的数据(比如数组)非常方便。

2. 使用第一个元素获取数组首地址

我们已经学会了使用下标访问数组元素:

#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    printf("%d\n", arr[0]);
    printf("%d\n", arr[1]);
    printf("%d\n", arr[2]);
    printf("%d\n", arr[3]);
    printf("%d\n", arr[4]);
    return 0;
}

既然数组元素在内存中是连续排布的,第一个元素的地址就是整个数组的首地址。我们可以用取地址运算符 `&` 来获取第一个元素的地址:

int *p = &arr[0]; // 从第一个元素获取数组首地址

然后使用指针进行操作:

```
p;        // 指向第一个元素
p + 1;    // 指向第二个元素
p + 2;    // 指向第三个元素
p + 3;    // 指向第四个元素
p + 4;    // 指向第五个元素
```

通过取值运算符 `*`,可以访问或修改目标数据对象:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    int *p = &arr[0];
    printf("%d\n", *p);       // 第一个元素
    printf("%d\n", *(p + 1)); // 第二个元素
    printf("%d\n", *(p + 2)); // 第三个元素
    printf("%d\n", *(p + 3)); // 第四个元素
    printf("%d\n", *(p + 4)); // 第五个元素
    return 0;
}
```

注意,表达式 `p + 1` 必须先用括号包裹起来,然后再用取值运算符 `*`。这是因为 `*` 的优先级高于加法运算符:

```
*(p + 1) // 正确
*p + 1   // 错误,这会对指针解引用的值再加1
```

 3. 使用数组名获取数组首地址

我们还可以通过数组名直接获取数组的首地址:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    printf("arr = %u\n", arr);
    printf("&arr[0] = %u\n", &arr[0]);
    return 0;
}
```

`arr` 和 `&arr[0]` 都表示数组的首地址,那么我们可以直接将 `arr` 赋值给指针:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    int *p = arr;
    printf("%d\n", *p);       // 第一个元素
    printf("%d\n", *(p + 1)); // 第二个元素
    printf("%d\n", *(p + 2)); // 第三个元素
    printf("%d\n", *(p + 3)); // 第四个元素
    printf("%d\n", *(p + 4)); // 第五个元素
    return 0;
}
```

虽然这些操作成功了,但这并不意味着数组名是一个指针。我们通过 `sizeof` 可以验证这一点:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    int *p = arr;
    printf("sizeof arr = %d\n", sizeof(arr));    // 输出20
    printf("sizeof p = %d\n", sizeof(p));        // 输出4(假设是32位系统)
    printf("sizeof arr + 1 = %d\n", sizeof(arr + 1)); //输出4
    return 0;
}
```

数组名 `arr` 在代码中使用时,会被转换为指向数组第一个元素的指针。但在以下两种情况下不会:
1. 对数组名使用 `sizeof` 操作。
2. 对数组名使用 `&` 操作。

 4. 使用指针访问数组等价于下标访问

通过下面的例子,我们可以看到使用指针访问数组和使用下标访问数组是等价的:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    printf("%d\n", arr[0]);      // 第一个元素
    printf("%d\n", arr[1]);      // 第二个元素
    printf("%d\n", arr[2]);      // 第三个元素
    printf("%d\n", arr[3]);      // 第四个元素
    printf("%d\n", arr[4]);      // 第五个元素
    printf("%d\n", *arr);        // 第一个元素
    printf("%d\n", *(arr + 1));  // 第二个元素
    printf("%d\n", *(arr + 2));  // 第三个元素
    printf("%d\n", *(arr + 3));  // 第四个元素
    printf("%d\n", *(arr + 4));  // 第五个元素
    return 0;
}
```

`arr[k]` 实际上会被编译器解读为 `*(arr + k)`。我们通过一个小测试来验证这个规则:

```
#include <stdio.h>

int main() {
    int arr[5] = {111, 222, 333, 444, 555};
    printf("arr[2] = %d\n", arr[2]);
    printf("2[arr] = %d\n", 2[arr]);
    printf("*(arr + 2) = %d\n", *(arr + 2));
    return 0;
}
```

运行结果验证了 `arr[2]` 和 `2[arr]` 是等价的,都是访问数组的第三个元素。

总结起来,我们学会了两种访问数组的方法:
1. `数组名[下标]`
2. `*(数组名 + 偏移量)`

这两种方式在功能上是完全等价的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值