structs.c 完整代码
#include<stdio.h>#include<string.h>// 结构体定义structStudent{charname[50];intid;floatgpa;};// 嵌套结构体定义structDate{intday;intmonth;intyear;};structEmployee{charname[50];intemployeeId;structDatehireDate;floatsalary;};// 函数声明voidprintStudent(structStudents);voidupdateGPA(structStudent*s,floatnewGPA);intmain(){// 结构体变量声明与初始化structStudents1={"张三",1001,3.8};// 结构体变量访问printf("=== 学生信息 ===\n");printf("姓名: %s\n",s1.name);printf("学号: %d\n",s1.id);printf("GPA: %.2f\n",s1.gpa);// 结构体指针structStudent*ptr=&s1;printf("\n=== 通过指针访问学生信息 ===\n");printf("姓名: %s\n",ptr->name);printf("学号: %d\n",ptr->id);printf("GPA: %.2f\n",ptr->gpa);// 结构体数组printf("\n=== 学生数组 ===\n");structStudentstudents[3]={{"李四",1002,3.5},{"王五",1003,3.9},{"赵六",1004,3.2}};for(inti=0;i<3;i++){printStudent(students[i]);}// 调用函数修改结构体成员printf("\n=== 修改GPA ===\n");updateGPA(&students[0],3.7);printStudent(students[0]);// 嵌套结构体示例printf("\n=== 员工信息(嵌套结构体)===\n");structEmployeeemp1;strcpy(emp1.name,"钱七");emp1.employeeId=2001;emp1.hireDate.day=15;emp1.hireDate.month=6;emp1.hireDate.year=2020;emp1.salary=5000.0;printf("员工姓名: %s\n",emp1.name);printf("员工ID: %d\n",emp1.employeeId);printf("入职日期: %d/%d/%d\n",emp1.hireDate.day,emp1.hireDate.month,emp1.hireDate.year);printf("薪资: %.2f\n",emp1.salary);return0;}// 函数定义:打印学生信息voidprintStudent(structStudents){printf("姓名: %s, 学号: %d, GPA: %.2f\n",s.name,s.id,s.gpa);}// 函数定义:更新GPA(使用指针修改原结构体)voidupdateGPA(structStudent*s,floatnewGPA){s->gpa=newGPA;}1. 文件概述
structs.c 是一个展示 C 语言中结构体基本概念、定义和使用方法的示例文件。通过该文件,您可以学习 C 语言中结构体的定义、初始化、访问、结构体指针、结构体数组以及嵌套结构体等核心操作。
- 文件名: structs.c
- 类型: C语言源文件
- 功能: 演示C语言中结构体的基本概念、定义和使用方法,包括基本结构体、嵌套结构体、结构体数组、结构体指针以及结构体作为函数参数等。
- 依赖: 标准C库(stdio.h, string.h)
2. 核心结构
2.1 头文件包含
structs.c 首先包含了两个必要的头文件:
#include<stdio.h>// 引入标准输入输出库#include<string.h>// 引入字符串处理函数库(用于字符串复制操作)2.2 结构体定义
2.2.1 基本结构体
Student 结构体用于表示学生信息,包含姓名、学号和GPA三个成员:
// 结构体定义structStudent{charname[50];// 学生姓名intid;// 学生学号floatgpa;// 学生GPA};2.2.2 嵌套结构体
Date 结构体用于表示日期,包含日、月、年三个成员:
// 嵌套结构体定义structDate{intday;// 日期intmonth;// 月份intyear;// 年份};Employee 结构体用于表示员工信息,包含姓名、员工ID、入职日期(Date结构体)和薪资四个成员:
structEmployee{charname[50];// 员工姓名intemployeeId;// 员工IDstructDatehireDate;// 入职日期(嵌套Date结构体)floatsalary;// 员工薪资};2.3 函数声明
structs.c 声明了两个用于处理 Student 结构体的函数:
// 函数声明voidprintStudent(structStudents);// 打印学生信息(值传递)voidupdateGPA(structStudent*s,floatnewGPA);// 更新学生GPA(指针传递,修改原结构体)2.4 主函数(程序入口)
程序的核心逻辑在main()函数中实现,该函数演示了各种结构体操作并输出结果:
intmain(){// 结构体变量声明与初始化structStudents1={"张三",1001,3.8};// 结构体变量访问printf("=== 学生信息 ===\n");printf("姓名: %s\n",s1.name);printf("学号: %d\n",s1.id);printf("GPA: %.2f\n",s1.gpa);// 结构体指针structStudent*ptr=&s1;printf("\n=== 通过指针访问学生信息 ===\n");printf("姓名: %s\n",ptr->name);printf("学号: %d\n",ptr->id);printf("GPA: %.2f\n",ptr->gpa);// 结构体数组printf("\n=== 学生数组 ===\n");structStudentstudents[3]={{"李四",1002,3.5},{"王五",1003,3.9},{"赵六",1004,3.2}};for(inti=0;i<3;i++){printStudent(students[i]);}// 调用函数修改结构体成员printf("\n=== 修改GPA ===\n");updateGPA(&students[0],3.7);printStudent(students[0]);// 嵌套结构体示例printf("\n=== 员工信息(嵌套结构体)===\n");structEmployeeemp1;strcpy(emp1.name,"钱七");emp1.employeeId=2001;emp1.hireDate.day=15;emp1.hireDate.month=6;emp1.hireDate.year=2020;emp1.salary=5000.0;printf("员工姓名: %s\n",emp1.name);printf("员工ID: %d\n",emp1.employeeId);printf("入职日期: %d/%d/%d\n",emp1.hireDate.day,emp1.hireDate.month,emp1.hireDate.year);printf("薪资: %.2f\n",emp1.salary);return0;}3. 关键概念与实现
3.1 结构体的定义与声明
结构体是 C 语言中一种用户自定义的数据类型,用于将不同类型的数据组合在一起。其基本语法如下:
struct结构体名{数据类型 成员名1;数据类型 成员名2;// ...};在 structs.c 中,我们定义了三个结构体:
struct Student:表示学生信息struct Date:表示日期struct Employee:表示员工信息(包含嵌套的 Date 结构体)
3.2 嵌套结构体
嵌套结构体是指在一个结构体内部包含另一个结构体类型的成员。在 structs.c 中,Employee结构体包含了一个Date结构体作为其成员:
structEmployee{charname[50];intemployeeId;structDatehireDate;// 嵌套 Date 结构体floatsalary;};嵌套结构体允许我们更自然地组织相关数据,例如员工的入职日期可以作为员工信息的一部分。
3.3 结构体变量的初始化
结构体变量可以在声明时直接初始化,使用大括号{}来指定各个成员的值:
// 直接初始化结构体变量structStudents1={"张三",1001,3.8};也可以先声明结构体变量,然后再逐个初始化其成员:
// 先声明结构体变量structEmployeeemp1;// 然后逐个初始化成员strcpy(emp1.name,"钱七");emp1.employeeId=2001;emp1.hireDate.day=15;emp1.hireDate.month=6;emp1.hireDate.year=2020;emp1.salary=5000.0;3.4 结构体成员的访问
要访问结构体变量的成员,可以使用点运算符.:
printf("姓名: %s\n",s1.name);printf("学号: %d\n",s1.id);printf("GPA: %.2f\n",s1.gpa);对于嵌套结构体的成员访问,需要使用多个点运算符:
printf("入职日期: %d/%d/%d\n",emp1.hireDate.day,emp1.hireDate.month,emp1.hireDate.year);3.5 结构体指针
结构体指针是指向结构体变量的指针,使用箭头运算符->来访问结构体成员:
// 结构体指针structStudent*ptr=&s1;printf("姓名: %s\n",ptr->name);printf("学号: %d\n",ptr->id);printf("GPA: %.2f\n",ptr->gpa);结构体指针在函数参数传递中非常有用,可以避免结构体的复制开销,并允许函数修改原结构体的值。
3.6 结构体数组
结构体数组是元素为结构体类型的数组,可以使用嵌套的大括号来初始化:
// 结构体数组structStudentstudents[3]={{"李四",1002,3.5},{"王五",1003,3.9},{"赵六",1004,3.2}};要访问结构体数组中的元素及其成员,可以结合数组下标和点运算符:
for(inti=0;i<3;i++){printStudent(students[i]);}3.7 结构体作为函数参数
结构体可以作为函数参数传递,有两种传递方式:
3.7.1 值传递
值传递将结构体变量的副本传递给函数,函数内部的修改不会影响原结构体变量:
// 函数定义:打印学生信息(值传递)voidprintStudent(structStudents){printf("姓名: %s, 学号: %d, GPA: %.2f\n",s.name,s.id,s.gpa);}3.7.2 指针传递
指针传递将结构体变量的地址传递给函数,函数内部可以通过指针修改原结构体变量:
// 函数定义:更新GPA(使用指针修改原结构体)voidupdateGPA(structStudent*s,floatnewGPA){s->gpa=newGPA;// 使用箭头运算符访问指针指向的结构体成员}指针传递比值传递更高效,特别是当结构体较大时,可以避免大量数据的复制。
4. 代码流程
structs.c 的执行流程如下:
- 引入头文件
stdio.h和string.h - 定义 Student 结构体
- 定义 Date 结构体和嵌套的 Employee 结构体
- 声明 printStudent 和 updateGPA 函数
- 主函数入口:
- 声明并初始化 Student 结构体变量 s1
- 直接访问 s1 的成员并输出
- 创建指向 s1 的指针并通过指针访问成员
- 声明并初始化 Student 结构体数组
- 调用 printStudent 函数打印数组中每个学生的信息
- 调用 updateGPA 函数修改第一个学生的GPA
- 声明并初始化 Employee 嵌套结构体变量
- 访问并输出 Employee 及其内部 Date 结构体的成员
- 程序结束
5. 输出结果
编译并运行 structs.c 后,将得到以下输出:
=== 学生信息 === 姓名: 张三 学号: 1001 GPA: 3.80 === 通过指针访问学生信息 === 姓名: 张三 学号: 1001 GPA: 3.80 === 学生数组 === 姓名: 李四, 学号: 1002, GPA: 3.50 姓名: 王五, 学号: 1003, GPA: 3.90 姓名: 赵六, 学号: 1004, GPA: 3.20 === 修改GPA === 姓名: 李四, 学号: 1002, GPA: 3.70 === 员工信息(嵌套结构体)=== 员工姓名: 钱七 员工ID: 2001 入职日期: 15/6/2020 薪资: 5000.006. 补充代码示例
6.1 结构体的动态内存分配
使用malloc()函数为结构体动态分配内存:
#include<stdio.h>#include<stdlib.h>#include<string.h>structStudent{charname[50];intid;floatgpa;};intmain(){// 动态分配结构体内存structStudent*ptr=(structStudent*)malloc(sizeof(structStudent));if(ptr==NULL){printf("内存分配失败\n");return1;}// 初始化结构体成员strcpy(ptr->name,"孙八");ptr->id=1005;ptr->gpa=3.6;// 访问结构体成员printf("姓名: %s\n",ptr->name);printf("学号: %d\n",ptr->id);printf("GPA: %.2f\n",ptr->gpa);// 释放动态分配的内存free(ptr);return0;}6.2 结构体的 typedef
使用typedef关键字为结构体类型创建别名,简化结构体的使用:
#include<stdio.h>#include<string.h>// 使用 typedef 为结构体创建别名typedefstruct{charname[50];intid;floatgpa;}Student;// Student 是结构体的别名// 使用 typedef 为嵌套结构体创建别名typedefstruct{intday;intmonth;intyear;}Date;typedefstruct{charname[50];intemployeeId;Date hireDate;// 使用别名 Datefloatsalary;}Employee;// Employee 是结构体的别名intmain(){// 直接使用别名创建结构体变量Student s1={"周九",1006,3.8};Employee emp1;strcpy(emp1.name,"吴十");emp1.employeeId=2002;emp1.hireDate.day=20;emp1.hireDate.month=8;emp1.hireDate.year=2021;emp1.salary=5500.0;printf("学生姓名: %s\n",s1.name);printf("员工姓名: %s\n",emp1.name);printf("入职日期: %d/%d/%d\n",emp1.hireDate.day,emp1.hireDate.month,emp1.hireDate.year);return0;}6.3 结构体数组的动态内存分配
使用malloc()函数为结构体数组动态分配内存:
#include<stdio.h>#include<stdlib.h>#include<string.h>structStudent{charname[50];intid;floatgpa;};intmain(){intn=3;// 动态分配结构体数组内存structStudent*students=(structStudent*)malloc(n*sizeof(structStudent));if(students==NULL){printf("内存分配失败\n");return1;}// 初始化结构体数组strcpy(students[0].name,"郑十一");students[0].id=1007;students[0].gpa=3.9;strcpy(students[1].name,"王十二");students[1].id=1008;students[1].gpa=3.7;strcpy(students[2].name,"赵十三");students[2].id=1009;students[2].gpa=3.5;// 访问结构体数组for(inti=0;i<n;i++){printf("学生 %d: %s, %d, %.2f\n",i+1,students[i].name,students[i].id,students[i].gpa);}// 释放动态分配的内存free(students);return0;}7. 编译和运行
7.1 使用 GCC 编译
在命令行中,可以使用以下命令编译 structs.c:
gcc structs.c -o structs -fexec-charset=gbk7.2 运行程序
编译成功后,根据您的操作系统,使用以下命令运行程序:
Windows:
.\structs.exeLinux/macOS:
./structs
8. 注意事项
8.1 结构体成员的访问
- 直接访问结构体变量的成员使用点运算符
. - 访问结构体指针指向的成员使用箭头运算符
->
8.2 字符串成员的初始化
对于结构体中的字符串成员,不能直接使用赋值运算符=来初始化或修改,需要使用strcpy()函数:
// 错误的方式emp1.name="钱七";// 字符串数组不能直接赋值// 正确的方式strcpy(emp1.name,"钱七");// 使用 strcpy 函数复制字符串8.3 结构体的大小
结构体的大小可能大于其所有成员大小的总和,这是因为编译器为了提高访问效率会对结构体成员进行内存对齐。可以使用sizeof()运算符来获取结构体的实际大小。
8.4 内存管理
如果使用malloc()等函数动态分配了结构体内存,必须使用free()函数及时释放内存,避免内存泄漏。
9. 总结
structs.c 提供了 C 语言中结构体操作的基本示例,涵盖了结构体的定义、初始化、访问、嵌套、指针、数组以及作为函数参数等核心概念。通过学习这些示例,您可以掌握 C 语言中结构体处理的基础知识。
此外,我们还补充了结构体的动态内存分配、typedef 别名以及结构体数组的动态内存分配等高级操作的示例代码,帮助您进一步扩展对 C 语言结构体处理的理解。
在实际编程中,结构体是一种非常重要的数据类型,它允许我们将相关的数据组织在一起,提高代码的可读性和可维护性。特别是在处理复杂数据结构(如链表、树等)时,结构体是不可或缺的基础。