Appearance
结构体
结构体是C语言中用于组合不同类型数据的数据结构。通过结构体,可以将相关的数据组织在一起,形成自定义的数据类型。本章将详细介绍结构体、联合体和枚举的使用。
结构体基础
结构体的定义
c
/*
* 结构体的定义和使用
*/
#include <stdio.h>
#include <string.h>
/* 定义结构体类型 */
struct Student {
char name[50]; /* 姓名 */
int age; /* 年龄 */
float score; /* 成绩 */
};
/* 使用typedef定义结构体别名 */
typedef struct {
int x;
int y;
} Point;
/* 嵌套结构体 */
struct Date {
int year;
int month;
int day;
};
struct Person {
char name[50];
struct Date birthday; /* 嵌套的结构体 */
};
int main(void)
{
/* 声明结构体变量 */
struct Student stu1;
/* 初始化方式1:逐个赋值 */
strcpy(stu1.name, "张三");
stu1.age = 20;
stu1.score = 85.5;
/* 初始化方式2:声明时初始化 */
struct Student stu2 = {"李四", 21, 90.0};
/* 初始化方式3:指定成员初始化(C99) */
struct Student stu3 = {
.name = "王五",
.age = 22,
.score = 88.0
};
/* 访问结构体成员 */
printf("学生1: %s, %d岁, 成绩%.1f\n",
stu1.name, stu1.age, stu1.score);
printf("学生2: %s, %d岁, 成绩%.1f\n",
stu2.name, stu2.age, stu2.score);
/* 使用typedef定义的结构体 */
Point p1 = {10, 20};
Point p2 = {.x = 5, .y = 15};
printf("\n点1: (%d, %d)\n", p1.x, p1.y);
printf("点2: (%d, %d)\n", p2.x, p2.y);
/* 嵌套结构体 */
struct Person person = {
"张三",
{2000, 5, 15}
};
printf("\n姓名: %s\n", person.name);
printf("生日: %d年%d月%d日\n",
person.birthday.year,
person.birthday.month,
person.birthday.day);
return 0;
}结构体数组
c
/*
* 结构体数组
*/
#include <stdio.h>
#include <string.h>
/* 定义结构体 */
struct Student {
char name[50];
int age;
float score;
};
/* 打印学生信息 */
void print_student(struct Student s)
{
printf("%-10s %3d %6.1f\n", s.name, s.age, s.score);
}
int main(void)
{
/* 声明结构体数组 */
struct Student class1[3];
/* 初始化数组元素 */
strcpy(class1[0].name, "张三");
class1[0].age = 20;
class1[0].score = 85.5;
strcpy(class1[1].name, "李四");
class1[1].age = 21;
class1[1].score = 90.0;
strcpy(class1[2].name, "王五");
class1[2].age = 19;
class1[2].score = 78.5;
/* 声明时初始化 */
struct Student class2[] = {
{"赵六", 22, 88.0},
{"钱七", 20, 92.5},
{"孙八", 21, 76.0}
};
/* 遍历结构体数组 */
printf("班级1学生信息:\n");
printf("%-10s %3s %6s\n", "姓名", "年龄", "成绩");
for (int i = 0; i < 3; i++) {
print_student(class1[i]);
}
/* 计算平均成绩 */
float total = 0;
int count = sizeof(class2) / sizeof(class2[0]);
for (int i = 0; i < count; i++) {
total += class2[i].score;
}
printf("\n班级2平均成绩: %.2f\n", total / count);
return 0;
}结构体指针
c
/*
* 结构体指针
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student {
char name[50];
int age;
float score;
};
/* 通过指针访问结构体成员 */
void print_student_ptr(struct Student *s)
{
/* 使用 -> 运算符 */
printf("姓名: %s\n", s->name);
printf("年龄: %d\n", s->age);
printf("成绩: %.1f\n", s->score);
/* 等价于 (*s).name */
printf("(*s).name = %s\n", (*s).name);
}
/* 通过指针修改结构体 */
void update_score(struct Student *s, float new_score)
{
s->score = new_score;
}
int main(void)
{
struct Student stu = {"张三", 20, 85.5};
struct Student *ptr = &stu;
/* 使用指针访问成员 */
printf("使用指针访问:\n");
printf("ptr->name = %s\n", ptr->name);
printf("ptr->age = %d\n", ptr->age);
printf("ptr->score = %.1f\n", ptr->score);
/* 通过指针修改 */
ptr->age = 21;
printf("\n修改后年龄: %d\n", stu.age);
/* 动态分配结构体 */
struct Student *dynamic_stu = (struct Student*)malloc(sizeof(struct Student));
if (dynamic_stu != NULL) {
strcpy(dynamic_stu->name, "李四");
dynamic_stu->age = 22;
dynamic_stu->score = 90.0;
printf("\n动态分配的结构体:\n");
print_student_ptr(dynamic_stu);
free(dynamic_stu);
}
/* 结构体指针数组 */
struct Student *students[3];
struct Student s1 = {"张三", 20, 85};
struct Student s2 = {"李四", 21, 90};
struct Student s3 = {"王五", 22, 88};
students[0] = &s1;
students[1] = &s2;
students[2] = &s3;
printf("\n结构体指针数组:\n");
for (int i = 0; i < 3; i++) {
printf("%s: %.1f分\n", students[i]->name, students[i]->score);
}
return 0;
}结构体与函数
c
/*
* 结构体作为函数参数和返回值
*/
#include <stdio.h>
#include <string.h>
struct Point {
int x;
int y;
};
/* 结构体作为参数(值传递) */
void print_point(struct Point p)
{
printf("(%d, %d)\n", p.x, p.y);
}
/* 结构体指针作为参数(地址传递) */
void move_point(struct Point *p, int dx, int dy)
{
p->x += dx;
p->y += dy;
}
/* 返回结构体 */
struct Point create_point(int x, int y)
{
struct Point p = {x, y};
return p;
}
/* 返回结构体指针(动态分配) */
struct Point *create_point_dynamic(int x, int y)
{
struct Point *p = (struct Point*)malloc(sizeof(struct Point));
if (p != NULL) {
p->x = x;
p->y = y;
}
return p;
}
/* 结构体数组作为参数 */
void print_points(struct Point points[], int n)
{
for (int i = 0; i < n; i++) {
printf("Point %d: (%d, %d)\n", i, points[i].x, points[i].y);
}
}
int main(void)
{
struct Point p1 = {10, 20};
/* 值传递 */
printf("值传递:\n");
print_point(p1);
/* 指针传递 */
printf("\n移动前: ");
print_point(p1);
move_point(&p1, 5, -5);
printf("移动后: ");
print_point(p1);
/* 返回结构体 */
printf("\n创建新点:\n");
struct Point p2 = create_point(30, 40);
print_point(p2);
/* 返回结构体指针 */
struct Point *p3 = create_point_dynamic(50, 60);
if (p3 != NULL) {
printf("\n动态创建的点: ");
print_point(*p3);
free(p3);
}
return 0;
}联合体
c
/*
* 联合体(共用体)
*/
#include <stdio.h>
/* 联合体:所有成员共享同一块内存 */
union Data {
int i;
float f;
char c;
char str[4];
};
/* 联合体的大小是最大成员的大小 */
int main(void)
{
union Data data;
printf("联合体大小: %zu 字节\n", sizeof(union Data));
printf("int大小: %zu\n", sizeof(int));
printf("float大小: %zu\n", sizeof(float));
printf("char大小: %zu\n", sizeof(char));
/* 存储整数 */
data.i = 10;
printf("\n存储整数: %d\n", data.i);
/* 存储浮点数(覆盖之前的值) */
data.f = 3.14f;
printf("存储浮点数: %f\n", data.f);
printf("此时整数: %d(无意义)\n", data.i);
/* 存储字符 */
data.c = 'A';
printf("\n存储字符: %c\n", data.c);
/* 实际应用:类型标记 */
struct Value {
int type; /* 0=int, 1=float, 2=char */
union {
int i_val;
float f_val;
char c_val;
} data;
};
struct Value v1;
v1.type = 0;
v1.data.i_val = 100;
struct Value v2;
v2.type = 1;
v2.data.f_val = 3.14f;
printf("\n类型标记联合体:\n");
printf("v1: type=%d, value=", v1.type);
if (v1.type == 0) printf("%d\n", v1.data.i_val);
printf("v2: type=%d, value=", v2.type);
if (v2.type == 1) printf("%f\n", v2.data.f_val);
return 0;
}枚举
c
/*
* 枚举类型
*/
#include <stdio.h>
/* 定义枚举 */
enum WeekDay {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
};
/* 指定值的枚举 */
enum Month {
JANUARY = 1,
FEBRUARY = 2,
MARCH = 3,
APRIL = 4,
MAY = 5,
JUNE = 6,
JULY = 7,
AUGUST = 8,
SEPTEMBER = 9,
OCTOBER = 10,
NOVEMBER = 11,
DECEMBER = 12
};
/* 枚举在结构体中的应用 */
struct Task {
char name[50];
enum {
TODO,
IN_PROGRESS,
DONE
} status;
int priority;
};
/* 使用typedef定义枚举别名 */
typedef enum {
RED,
GREEN,
BLUE
} Color;
/* 枚举作为函数参数 */
const char* get_weekday_name(enum WeekDay day)
{
switch (day) {
case SUNDAY: return "星期日";
case MONDAY: return "星期一";
case TUESDAY: return "星期二";
case WEDNESDAY: return "星期三";
case THURSDAY: return "星期四";
case FRIDAY: return "星期五";
case SATURDAY: return "星期六";
default: return "未知";
}
}
int main(void)
{
/* 使用枚举 */
enum WeekDay today = WEDNESDAY;
printf("今天是: %s (值=%d)\n", get_weekday_name(today), today);
/* 遍历枚举 */
printf("\n一周七天:\n");
for (enum WeekDay day = SUNDAY; day <= SATURDAY; day++) {
printf("%d: %s\n", day, get_weekday_name(day));
}
/* 枚举在结构体中 */
struct Task task1 = {"写代码", IN_PROGRESS, 1};
struct Task task2 = {"测试", TODO, 2};
printf("\n任务列表:\n");
printf("%s: 状态=%d, 优先级=%d\n",
task1.name, task1.status, task1.priority);
/* 使用typedef的枚举 */
Color favorite = BLUE;
printf("\n喜欢的颜色: %d\n", favorite);
return 0;
}位域
c
/*
* 位域(位字段)
*/
#include <stdio.h>
/* 位域结构体 */
struct Flags {
unsigned int ready : 1; /* 1位 */
unsigned int error : 1; /* 1位 */
unsigned int mode : 2; /* 2位,可存储0-3 */
unsigned int count : 4; /* 4位,可存储0-15 */
};
/* 实际应用:IP地址头 */
struct IPHeader {
unsigned int version : 4; /* 版本号 */
unsigned int header_len : 4; /* 头长度 */
unsigned int tos : 8; /* 服务类型 */
unsigned int total_len : 16; /* 总长度 */
};
int main(void)
{
struct Flags f;
/* 设置位域值 */
f.ready = 1;
f.error = 0;
f.mode = 3; /* 最大值是3(2位) */
f.count = 15; /* 最大值是15(4位) */
printf("位域结构体大小: %zu 字节\n", sizeof(struct Flags));
printf("\nFlags值:\n");
printf("ready: %u\n", f.ready);
printf("error: %u\n", f.error);
printf("mode: %u\n", f.mode);
printf("count: %u\n", f.count);
/* 超出范围的值会被截断 */
f.count = 20; /* 20 = 10100,只存储低4位0100 = 4 */
printf("\ncount = 20后: %u(被截断)\n", f.count);
return 0;
}小结
本章学习了:
- 结构体:定义、初始化、成员访问、结构体数组、结构体指针
- 结构体与函数:值传递、指针传递、返回结构体
- 联合体:共享内存,节省空间
- 枚举:命名常量,提高代码可读性
- 位域:节省内存空间
下一章,我们将学习文件操作,了解C语言的文件读写操作。
