结构体单独用已经很方便,但真正形成战斗力的是三种组合:结构体指针、结构体数组、嵌套结构体。下面一次讲完这三样。
结构体指针:用 -> 访问成员
结构体变量有地址,自然也有指向它的指针:
struct name {
member1;
member2;
};
int main() {
struct name *ptr, Harry;
}这里 ptr 是指向 struct name 的指针。用指针访问成员时用箭头运算符 ->:
#include <stdio.h>
struct person {
int age;
float weight;
};
int main() {
struct person *personPtr, person1;
personPtr = &person1;
printf("输入年龄: ");
scanf("%d", &personPtr->age);
printf("输入体重: ");
scanf("%f", &personPtr->weight);
printf("显示:\n");
printf("年龄: %d\n", personPtr->age);
printf("体重: %f", personPtr->weight);
return 0;
}输出:
输入年龄: 25
输入体重: 55
显示:
年龄: 25
体重: 55.000000personPtr->age 完全等价于 (*personPtr).age,先解引用拿到结构体,再用点访问成员。箭头只是更简洁的写法。
动态分配结构体数组
人数不确定时用 malloc 动态分配一批结构体,然后靠 (ptr+i)->xxx 逐条访问:
#include <stdio.h>
#include <stdlib.h>
struct person {
int age;
float weight;
char name[30];
};
int main() {
struct person *ptr;
int i, n;
printf("输入人数: ");
scanf("%d", &n);
// 为 n 个 struct person 分配内存
ptr = (struct person *)malloc(n * sizeof(struct person));
for (i = 0; i < n; ++i) {
printf("分别输入姓名和年龄: ");
scanf("%s %d", (ptr + i)->name, &(ptr + i)->age);
}
printf("显示信息:\n");
for (i = 0; i < n; ++i)
printf("姓名: %s\t年龄: %d\n", (ptr + i)->name, (ptr + i)->age);
free(ptr);
return 0;
}先为 n 个结构体分配一块连续内存,再用指针算术访问第 i 个元素,这和数组操作是一回事。
结构体数组:批量存同类实体
要存 5 个学生,声明 5 个变量 s1..s5 会写到手抽筋。直接声明一个结构体数组:
#include <stdio.h>
#include <string.h>
struct student {
int rollno;
char name[10];
};
int main() {
int i;
struct student st[5];
printf("输入5个学生数据");
for (i = 0; i < 5; i++) {
printf("\n输入序号: ");
scanf("%d", &st[i].rollno);
printf("\n输入姓名: ");
scanf("%s", &st[i].name);
}
printf("\n学生信息列表:");
for (i = 0; i < 5; i++) {
printf("\n序号:%d, 姓名:%s", st[i].rollno, st[i].name);
}
return 0;
}输出:
输入5个学生数据
输入序号:1
输入姓名:Sonoo
输入序号:2
输入姓名:Ratan
...
学生信息列表:
序号:1, 姓名:Sonoo
序号:2, 姓名:Ratan
...结构体数组就是一组同类型的结构体变量,每个元素存不同实体的信息,配合下标 st[i] 访问成员。
嵌套结构体:结构体里的结构体
一个结构体的成员可以是另一个结构体。比如员工有地址,地址又包含城市、邮编、电话,把地址做成单独结构体,再嵌进员工:
struct address {
char city[20];
int pin;
char phone[14];
};
struct employee {
char name[20];
struct address add; // 嵌套地址结构体
};访问嵌套成员用练级式的点:外层.内层.成员:
#include <stdio.h>
struct address {
char city[20];
int pin;
char phone[14];
};
struct employee {
char name[20];
struct address add;
};
int main() {
struct employee emp;
printf("输入员工信息?\n");
scanf("%s %s %d %s", emp.name, emp.add.city,
&emp.add.pin, emp.add.phone);
printf("打印员工信息....\n");
printf("姓名: %s\n城市: %s\n编号: %d\n电话: %s\n",
emp.name, emp.add.city, emp.add.pin, emp.add.phone);
return 0;
}输出:
输入员工信息?
Arun
Delhi
110001
1234567890
打印员工信息....
姓名: Arun
城市: Delhi
编号: 110001
电话: 1234567890两种嵌套方式
- 分开定义结构体再嵌套:先写
struct Date { ... },再在 Employee 里放struct Date doj;。好处是 Date 可以被多个结构体复用。 - 内嵌声明:直接在结构体内部声明嵌套结构体,代码紧凑,但不能被其他结构体复用。
/* 方式一:分开定义(可复用) */
struct Date { int dd; int mm; int yyyy; };
struct Employee {
int id;
char name[20];
struct Date doj;
} emp1;
/* 方式二:内嵌声明(紧凑但不可复用) */
struct Employee {
int id;
char name[20];
struct Date {
int dd; int mm; int yyyy;
} doj;
} e1;访问嵌套成员就是一层层点下去:e1.doj.dd、e1.doj.mm、e1.doj.yyyy。
结构体也能传给函数
结构体可以整体传给函数(按值拷贝一份),成员也可以单独传:
void display(struct employee emp) {
printf("%s %s %d %s", emp.name, emp.add.city,
emp.add.pin, emp.add.phone);
}注意按值传递会整个拷贝结构体,结构体很大时开销不小,想省内存可以传指针(const struct employee *),见函数指针与按引用传参相关章节。
指针配合 -> 动态管理结构体,数组批量存储,嵌套表达层级数据,这三样组合起来,结构体才真正能组织起复杂数据。