C语言结构体详解:从入门到精通
1. 结构体基本概念
什么是结构体?
结构体是C语言中用户自定义的数据类型,允许将不同类型的数据组合成一个单一类型。
#include <stdio.h>
#include <string.h>
// 定义结构体类型
struct Student {
char name[50];
int age;
float grade;
char id[10];
};
int main() {
// 声明结构体变量
struct Student student1;
// 初始化结构体成员
strcpy(student1.name, "张三");
student1.age = 20;
student1.grade = 85.5;
strcpy(student1.id, "2024001");
// 访问结构体成员
printf("学生信息:\n");
printf("姓名: %s\n", student1.name);
printf("年龄: %d\n", student1.age);
printf("成绩: %.1f\n", student1.grade);
printf("学号: %s\n", student1.id);
return 0;
}
输出:
学生信息:
姓名: 张三
年龄: 20
成绩: 85.5
学号: 2024001
2. 结构体声明和初始化
2.1 多种声明方式
#include <stdio.h>
#include <string.h>
// 方式1:先定义类型,再声明变量
struct Point {
int x;
int y;
};
// 方式2:定义类型的同时声明变量
struct Rectangle {
int width;
int height;
} rect1, rect2;
// 方式3:使用typedef创建别名
typedef struct {
char title[100];
char author[50];
float price;
} Book;
int main() {
// 初始化结构体
struct Point p1 = {10, 20}; // 顺序初始化
struct Point p2 = {.y = 30, .x = 15}; // 指定成员初始化
// 声明后赋值
rect1.width = 100;
rect1.height = 50;
// 使用typedef别名
Book book1 = {"C语言教程", "李教授", 45.5};
printf("点p1: (%d, %d)\n", p1.x, p1.y);
printf("点p2: (%d, %d)\n", p2.x, p2.y);
printf("矩形: %dx%d\n", rect1.width, rect1.height);
printf("书籍: 《%s》作者:%s 价格:%.1f元\n",
book1.title, book1.author, book1.price);
return 0;
}
输出:
点p1: (10, 20)
点p2: (15, 30)
矩形: 100x50
书籍: 《C语言教程》作者:李教授 价格:45.5元
3. 结构体数组
3.1 结构体数组的使用
#include <stdio.h>
#include <string.h>
typedef struct {
char name[30];
int employee_id;
float salary;
char department[20];
} Employee;
int main() {
// 声明并初始化结构体数组
Employee employees[3] = {
{"张三", 1001, 8000.0, "技术部"},
{"李四", 1002, 7500.0, "市场部"},
{"王五", 1003, 9000.0, "技术部"}
};
printf("员工信息表:\n");
printf("%-10s %-8s %-10s %-12s\n", "姓名", "工号", "工资", "部门");
printf("----------------------------------------\n");
// 遍历结构体数组
for(int i = 0; i < 3; i++) {
printf("%-10s %-8d %-10.2f %-12s\n",
employees[i].name,
employees[i].employee_id,
employees[i].salary,
employees[i].department);
}
// 计算平均工资
float total_salary = 0;
for(int i = 0; i < 3; i++) {
total_salary += employees[i].salary;
}
printf("\n平均工资: %.2f元\n", total_salary / 3);
return 0;
}
输出:
员工信息表:
姓名 工号 工资 部门
----------------------------------------
张三 1001 8000.00 技术部
李四 1002 7500.00 市场部
王五 1003 9000.00 技术部
平均工资: 8166.67元
4. 结构体指针
4.1 结构体指针的使用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char model[50];
int year;
float price;
} Car;
int main() {
// 栈上结构体
Car car1 = {"Toyota Camry", 2023, 215000.0};
Car *car_ptr = &car1; // 指向结构体的指针
// 通过指针访问成员(两种方式)
printf("汽车信息:\n");
printf("型号: %s\n", (*car_ptr).model); // 方式1
printf("年份: %d\n", car_ptr->year); // 方式2(推荐)
printf("价格: %.2f\n", car_ptr->price);
// 动态分配结构体
Car *dynamic_car = (Car*)malloc(sizeof(Car));
if(dynamic_car != NULL) {
strcpy(dynamic_car->model, "Honda Accord");
dynamic_car->year = 2024;
dynamic_car->price = 198000.0;
printf("\n动态分配汽车:\n");
printf("型号: %s\n", dynamic_car->model);
printf("年份: %d\n", dynamic_car->year);
printf("价格: %.2f\n", dynamic_car->price);
free(dynamic_car); // 释放内存
}
return 0;
}
输出:
汽车信息:
型号: Toyota Camry
年份: 2023
价格: 215000.00
动态分配汽车:
型号: Honda Accord
年份: 2024
价格: 198000.00
5. 结构体与函数
5.1 结构体作为函数参数
#include <stdio.h>
#include <math.h>
typedef struct {
double real;
double imag;
} Complex;
// 结构体作为值传递
void printComplex(Complex c) {
printf("%.2f + %.2fi\n", c.real, c.imag);
}
// 结构体作为指针传递(避免复制开销)
Complex addComplex(Complex *a, Complex *b) {
Complex result;
result.real = a->real + b->real;
result.imag = a->imag + b->imag;
return result;
}
// 计算复数模长
double complexMagnitude(Complex *c) {
return sqrt(c->real * c->real + c->imag * c->imag);
}
int main() {
Complex num1 = {3.0, 4.0};
Complex num2 = {1.5, 2.5};
printf("复数1: ");
printComplex(num1);
printf("复数2: ");
printComplex(num2);
Complex sum = addComplex(&num1, &num2);
printf("相加结果: ");
printComplex(sum);
printf("复数1的模长: %.2f\n", complexMagnitude(&num1));
return 0;
}
输出:
复数1: 3.00 + 4.00i
复数2: 1.50 + 2.50i
相加结果: 4.50 + 6.50i
复数1的模长: 5.00
6. 结构体嵌套
6.1 嵌套结构体
#include <stdio.h>
#include <string.h>
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
char name[50];
Date birth_date;
struct { // 匿名结构体
char street[100];
char city[50];
char zip_code[10];
} address;
} Person;
int main() {
Person person1;
strcpy(person1.name, "王小明");
person1.birth_date.day = 15;
person1.birth_date.month = 8;
person1.birth_date.year = 1995;
strcpy(person1.address.street, "人民路123号");
strcpy(person1.address.city, "北京市");
strcpy(person1.address.zip_code, "100000");
printf("个人信息:\n");
printf("姓名: %s\n", person1.name);
printf("出生日期: %d年%d月%d日\n",
person1.birth_date.year,
person1.birth_date.month,
person1.birth_date.day);
printf("地址: %s%s (%s)\n",
person1.address.city,
person1.address.street,
person1.address.zip_code);
return 0;
}
输出:
个人信息:
姓名: 王小明
出生日期: 1995年8月15日
地址: 北京市人民路123号 (100000)
7. 结构体大小与内存对齐
7.1 结构体大小计算
#include <stdio.h>
struct Example1 {
char a; // 1字节
int b; // 4字节
char c; // 1字节
}; // 可能为12字节(对齐)
struct Example2 {
int b; // 4字节
char a; // 1字节
char c; // 1字节
}; // 可能为8字节(更紧凑)
#pragma pack(1) // 取消对齐
struct Example3 {
char a;
int b;
char c;
}; // 6字节(无对齐)
#pragma pack() // 恢复默认对齐
int main() {
printf("结构体大小:\n");
printf("Example1: %zu 字节\n", sizeof(struct Example1));
printf("Example2: %zu 字节\n", sizeof(struct Example2));
printf("Example3: %zu 字节\n", sizeof(struct Example3));
// 查看成员偏移量
struct Example1 ex1;
printf("\n成员偏移量:\n");
printf("a: %p\n", (void*)&ex1.a);
printf("b: %p\n", (void*)&ex1.b);
printf("c: %p\n", (void*)&ex1.c);
return 0;
}
输出:
结构体大小:
Example1: 12 字节
Example2: 8 字节
Example3: 6 字节
成员偏移量:
a: 0x7ffd3a4a4a30
b: 0x7ffd3a4a4a34
c: 0x7ffd3a4a4a38
8. 结构体高级特性
8.1 结构体位域
#include <stdio.h>
// 位域结构体
typedef struct {
unsigned int is_active : 1; // 1位
unsigned int priority : 3; // 3位 (0-7)
unsigned int type : 4; // 4位 (0-15)
unsigned int reserved : 24; // 24位保留
} PacketHeader;
typedef struct {
unsigned char red : 5; // 5位 (0-31)
unsigned char green : 6; // 6位 (0-63)
unsigned char blue : 5; // 5位 (0-31)
} RGB15;
int main() {
PacketHeader header;
header.is_active = 1;
header.priority = 5;
header.type = 12;
printf("数据包头部:\n");
printf("是否激活: %u\n", header.is_active);
printf("优先级: %u\n", header.priority);
printf("类型: %u\n", header.type);
printf("总大小: %zu 字节\n", sizeof(header));
RGB15 color;
color.red = 31; // 最大值
color.green = 63; // 最大值
color.blue = 31; // 最大值
printf("\nRGB颜色:\n");
printf("红色: %u\n", color.red);
printf("绿色: %u\n", color.green);
printf("蓝色: %u\n", color.blue);
printf("总大小: %zu 字节\n", sizeof(color));
return 0;
}
输出:
数据包头部:
是否激活: 1
优先级: 5
类型: 12
总大小: 4 字节
RGB颜色:
红色: 31
绿色: 63
蓝色: 31
总大小: 2 字节
9. 结构体实际应用
9.1 学生管理系统
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STUDENTS 100
typedef struct {
char name[50];
int id;
float scores[3]; // 三门课程成绩
float average;
} Student;
void inputStudent(Student *s) {
printf("请输入姓名: ");
scanf("%s", s->name);
printf("请输入学号: ");
scanf("%d", &s->id);
printf("请输入三门课程成绩: ");
scanf("%f %f %f", &s->scores[0], &s->scores[1], &s->scores[2]);
// 计算平均分
s->average = (s->scores[0] + s->scores[1] + s->scores[2]) / 3.0;
}
void printStudent(const Student *s) {
printf("%-10s %-8d %-6.1f %-6.1f %-6.1f %-6.1f\n",
s->name, s->id,
s->scores[0], s->scores[1], s->scores[2],
s->average);
}
void findTopStudent(Student students[], int count) {
int top_index = 0;
for(int i = 1; i < count; i++) {
if(students[i].average > students[top_index].average) {
top_index = i;
}
}
printf("\n最高分学生:\n");
printStudent(&students[top_index]);
}
int main() {
Student students[MAX_STUDENTS];
int count;
printf("请输入学生数量: ");
scanf("%d", &count);
if(count > MAX_STUDENTS) {
printf("数量超过最大值!\n");
return 1;
}
// 输入学生信息
for(int i = 0; i < count; i++) {
printf("\n学生 %d:\n", i + 1);
inputStudent(&students[i]);
}
// 显示所有学生
printf("\n%-10s %-8s %-6s %-6s %-6s %-6s\n",
"姓名", "学号", "成绩1", "成绩2", "成绩3", "平均分");
printf("------------------------------------------------\n");
for(int i = 0; i < count; i++) {
printStudent(&students[i]);
}
// 查找最高分学生
findTopStudent(students, count);
return 0;
}
输出示例:
请输入学生数量: 2
学生 1:
请输入姓名: 张三
请输入学号: 1001
请输入三门课程成绩: 85 90 78
学生 2:
请输入姓名: 李四
请输入学号: 1002
请输入三门课程成绩: 92 88 95
姓名 学号 成绩1 成绩2 成绩3 平均分
------------------------------------------------
张三 1001 85.0 90.0 78.0 84.3
李四 1002 92.0 88.0 95.0 91.7
最高分学生:
李四 1002 92.0 88.0 95.0 91.7
10. 结构体与联合体
10.1 结构体中的联合体
#include <stdio.h>
#include <string.h>
typedef union {
int int_value;
float float_value;
char string_value[20];
} Data;
typedef struct {
int data_type; // 1-int, 2-float, 3-string
Data data;
} Variant;
void printVariant(Variant *v) {
printf("数据类型 %d: ", v->data_type);
switch(v->data_type) {
case 1:
printf("整数 %d\n", v->data.int_value);
break;
case 2:
printf("浮点数 %.2f\n", v->data.float_value);
break;
case 3:
printf("字符串 %s\n", v->data.string_value);
break;
default:
printf("未知类型\n");
}
}
int main() {
Variant vars[3];
vars[0].data_type = 1;
vars[0].data.int_value = 100;
vars[1].data_type = 2;
vars[1].data.float_value = 3.14159;
vars[2].data_type = 3;
strcpy(vars[2].data.string_value, "Hello World");
printf("变体类型示例:\n");
for(int i = 0; i < 3; i++) {
printVariant(&vars[i]);
}
printf("\n联合体大小: %zu 字节\n", sizeof(Data));
printf("变体结构体大小: %zu 字节\n", sizeof(Variant));
return 0;
}
输出:
变体类型示例:
数据类型 1: 整数 100
数据类型 2: 浮点数 3.14
数据类型 3: 字符串 Hello World
联合体大小: 20 字节
变体结构体大小: 24 字节
总结
关键知识点:
- 结构体定义:使用struct关键字,可配合typedef
- 成员访问:使用点运算符(.)或箭头运算符(->)
- 内存布局:注意内存对齐对大小的影响
- 嵌套结构:结构体中可以包含其他结构体
- 位域:节省内存的特殊用法
- 函数参数:可传递结构体值或指针
最佳实践:
- 使用typedef创建有意义的类型名
- 传递大结构体时使用指针避免复制开销
- 注意结构体内存对齐,合理安排成员顺序
- 使用位域节省内存,但要注意可移植性
- 结构体初始化时使用指定成员初始化提高可读性
结构体是C语言中组织复杂数据的核心工具,掌握好结构体对编写高质量的C程序至关重要!
1719

被折叠的 条评论
为什么被折叠?



