- 代码实现:
#include <stdio.h>
#include <string.h>
// 定义结构体
struct Student {
int id;
char name[20];
};
int main() {
// 创建并初始化结构体数组
struct Student students[3] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"}
};
// 定义指针指向数组首元素
struct Student *ptr = students;
// 假设第一个学生的id最大
struct Student *maxStudent = ptr;
// 使用指针和数组下标的混合方式遍历数组
for (int i = 0; i < 3; i++) {
if ((ptr + i)->id > maxStudent->id) {
maxStudent = ptr + i;
}
}
// 输出id最大的学生信息
printf("ID最大的学生信息: ID = %d, Name = %s\n", maxStudent->id, maxStudent->name);
return 0;
}
- 指针运算和数组下标引用协同工作原理:
- 指针运算:
ptr + i
这种形式是指针运算,它根据 struct Student
的大小来移动指针。因为 ptr
是指向 struct Student
类型的指针,ptr + i
会移动 i
个 struct Student
的大小,这样就可以访问到数组中的不同元素。例如,ptr
指向 students[0]
,ptr + 1
就指向 students[1]
。
- 数组下标引用:
(ptr + i)->id
这种写法结合了指针运算和结构体成员访问。(ptr + i)
定位到数组中的特定元素,然后 ->
操作符用于访问该结构体元素的成员 id
。它等价于 students[i].id
,这体现了指针运算和数组下标引用在访问结构体数组成员上的等效性。
- 可能遇到的陷阱:
- 指针越界:如果在
for
循环中 i
的取值超过了数组的大小(这里是3),使用 ptr + i
会导致指针越界访问,这可能会访问到未分配的内存,导致程序崩溃或出现未定义行为。
- 类型不匹配:如果指针
ptr
的类型与数组元素类型不一致,例如将 ptr
定义为 int *
而不是 struct Student *
,指针运算的步长就会出错,因为 int
和 struct Student
的大小不同,这也会导致未定义行为。
- 悬空指针:如果在指针运算过程中,数组
students
的内存被释放(例如在函数中局部定义的数组在函数结束时被释放),而指针 ptr
仍然指向这块已释放的内存,就会产生悬空指针,后续对 ptr
的访问同样会导致未定义行为。