C语言结构体(struct)的详细讲解

C语言结构体(struct)的详细讲解

目录

引言

1. 动态内存管理

2. 结构体

2.1 定义语法

2.2 定义示例

2.3 初始化

2.4 结构体赋值

2.5 结构体数组

2.6 结构体指针赋值

3. 学生管理系统

附:结构体变量的存储原理

总结

引言

当前文章介绍动态堆空间内存分配与释放,C语言结构体定义、初始化、赋值、结构体数组、结构体指针的相关知识点,最后通过一个学生管理系统综合练习结构体数组的使用。

1. 动态内存管理

C语言代码----->编译----->链接------>可执行的二进制文件(windows下xxx.exe) 二进制文件中的数据是如何摆放的? 文本数据段、静态数据段、全局数据段。

堆栈空间: 代码在运行的时候才有的空间。 栈空间: 系统负责申请,负责释放。比如: 函数形参变量、数组…… 堆空间: 程序员负责申请,负责释放。

#include <stdlib.h> //标准库头文件 void *malloc(int size); //内存申请。 形参表示申请的空间大小,返回值:申请的空间的地址 void free(void *p); //内存释放。 形参就是要释放的空间首地址。

动态空间申请示例。

动态空间申请 #include "stdio.h" #include "string.h" #include <stdlib.h> int main() { int *p=malloc(sizeof(int)); //申请空间 if(p!=NULL) { printf("申请的空间地址: 0x%X\n",p); *p=888; printf("%d\n",*p); } free(p); //释放空间 return 0; } 示例2: #include "stdio.h" #include "string.h" #include <stdlib.h> ​ char *func(void) { char*str=malloc(100); //char str[100]; if(str!=NULL) { strcpy(str,"1234567890"); printf("子函数打印:%s\n",str); //free(str); //释放空间 return str; } else { return NULL; } } ​ int main() { char *p=func(); printf("主函数打印:%s\n",p); return 0; } 2. 结构体 2.1 定义语法

结构体的概念: 可存放不同数据类型的集合。 比如: 存放一个班级学生的信息。 可以使用一个结构体存放一个学生的信息。 一个结构体数组存放整个班级的学习信息。 数组的概念: 可存放相同数据类型的集合。

结构体的定义语法:

//声明一种新类型-----数据类型 struct <结构体的名称> { <结构体的成员>1; <结构体的成员>2; ………… }; //最后有分号结束 ​ struct MyStruct { char a; int b; float c; char str[100]; }; 2.2 定义示例

结构体如何赋值? 如何访问结构体内部成员

#include "stdio.h" #include "string.h" #include <stdlib.h> ​ //定义结构体数据类型 struct MyStruct { char a; int b; float c; char str[100]; }; int main() { struct MyStruct data={'A',123,456.789,"abcd"}; //data就是结构体类型的变量 //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0; } 2.3 初始化 #include "stdio.h" #include "string.h" #include <stdlib.h> ​ //定义结构体数据类型 struct MyStruct { char a; int b; float c; char str[100]; }data={'A',123,456.789,"abcd"}; //data就是结构体类型的变量 ​ int main() { //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0; } 2.4 结构体赋值 //结构体变量访问内部成员的语法: . 点运算符 #include "stdio.h" #include "string.h" #include <stdlib.h> ​ //定义结构体数据类型 struct MyStruct { char a; int b; float c; char str[100]; }; ​ int main() { struct MyStruct data;//data就是结构体类型的变量 //成员单独赋值 data.a='A'; data.b=123; data.c=456.789; strcpy(data.str,"abcd"); //数组赋值 ​ //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0; } 2.5 结构体数组 结构体赋值分为两种标准: C89 、C99 结构体数组 #include "stdio.h" #include "string.h" #include <stdlib.h> ​ //定义结构体数据类型 struct MyStruct { char a; int b; float c; char str[100]; }; ​ int main() { struct MyStruct data[100];//data就是结构体数组类型变量 struct MyStruct data2[50]; ​ //成员单独赋值 data[0].a='A'; data[0].b=123; data[0].c=456.789; strcpy(data[0].str,"abcd"); //数组赋值 ​ //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data[0].a); printf("%d\n",data[0].b); printf("%f\n",data[0].c); printf("%s\n",data[0].str); return 0; } 2.6 结构体指针赋值 #include "stdio.h" #include "string.h" #include <stdlib.h> //定义结构体数据类型 struct MyStruct { char a; int b; float c; char str[100]; }; ​ int main() { //struct MyStruct buff[100]; //struct MyStruct *data=buff; //结构体指针类型变量 ​ struct MyStruct *data=malloc(sizeof(struct MyStruct)); data->a='A'; data->b=123; data->c=456.789; strcpy(data->str,"abcd"); ​ //结构体指针访问内部成员的变量 通过 -> 运算符。 printf("%c\n",data->a); printf("%d\n",data->b); printf("%f\n",data->c); printf("%s\n",data->str); return 0; } 3. 学生管理系统

作业: 学生管理系统

需求: (每一个功能都是使用函数进行封装) 1.实现从键盘上录入学生信息。 (姓名、性别、学号、成绩、电话号码) 2.将结构体里的学生信息全部打印出来。 3.实现根据学生的姓名或者学号查找学生,查找到之后打印出学生的具体信息。 4.根据学生的成绩对学生信息进行排序。 5.根据学号删除学生信息。

示例:

#include "stdio.h" #include "string.h" #include <stdlib.h> //定义存放学生信息的结构体类型 struct StuDentInfo { char Name[20]; //姓名 int number; //学号 char phone[20];//电话号码 }; //全局变量区域 unsigned int StuDentCnt=0; //记录已经录入的全部学生数量 //函数声明区域 void PrintStuDentInfoList(void); void InputStuDentInfo(struct StuDentInfo*info); void FindStuDentInfo(struct StuDentInfo*info); void SortStuDentInfo(struct StuDentInfo*info); void PrintStuDentInfo(struct StuDentInfo*info); int main() { struct StuDentInfo data[100]; //可以100位学生的信息 int number; while(1) { PrintStuDentInfoList(); //打印功能列表 scanf("%d",&number); printf("\n"); switch(number) { case 1: InputStuDentInfo(data); break; case 2: FindStuDentInfo(data); break; case 3: SortStuDentInfo(data); break; case 4: PrintStuDentInfo(data); break; case 5: break; default: printf("选择错误!\n\n"); break; } } return 0; } /* 函数功能: 打印学生管理系统的功能列表 */ void PrintStuDentInfoList(void) { printf("\n--------------学生管理系统功能列表----------------\n"); printf("1. 录入学生信息\n"); printf("2. 根据学号查找学生信息\n"); printf("3. 根据学号排序\n"); printf("4. 打印所有学生信息\n"); printf("5. 删除指定的学生信息\n"); printf("请选择功能序号:"); } /* 函数功能: 录入学生信息 */ void InputStuDentInfo(struct StuDentInfo*info) { printf("输入学生姓名:"); scanf("%s",info[StuDentCnt].Name); printf("输入学号:"); scanf("%d",&info[StuDentCnt].number); printf("输入电话号码:"); scanf("%s",info[StuDentCnt].phone); StuDentCnt++; //数量自增 } /* 函数功能: 查找学生信息 */ void FindStuDentInfo(struct StuDentInfo*info) { int num,i; printf("输入查找的学号:"); scanf("%d",&num); for(i=0; i<StuDentCnt; i++) { if(info[i].number==num) { printf("信息查找成功,该学生的信息如下:\n"); printf("姓名:%s\n",info[i].Name); printf("学号:%d\n",info[i].number); printf("电话号码:%s\n",info[i].phone); printf("\n"); break; } } if(i==StuDentCnt) { printf("----------%d学号不存在!---------\n",num); } } /* 函数功能: 根据学号排序 */ void SortStuDentInfo(struct StuDentInfo*info) { int i,j; struct StuDentInfo tmp; //保存临时信息 for(i=0; i<StuDentCnt-1; i++) { for(j=0;j<StuDentCnt-i-1;j++) { if(info[j].number>info[j+1].number) { tmp=info[j]; info[j]=info[j+1]; info[j+1]=tmp; } } } } /* 函数功能: 打印所有学生信息 */ void PrintStuDentInfo(struct StuDentInfo*info) { int i=0; printf("-----------所有学生的信息列表------------\n"); for(i=0;i<StuDentCnt;i++) { printf("姓名:%s\n",info[i].Name); printf("学号:%d\n",info[i].number); printf("电话号码:%s\n",info[i].phone); printf("\n"); } } 附:结构体变量的存储原理

1)结构体数据成员对齐的意义

内存是以字节为单位编号的,某些硬件平台对特定类型的数据的内存要求从特定的地址开始,如果数据的存放不符合其平台的要求,就会影响到访问效率。所以在内存中各类型的数据按照一定的规则在内存中存放,就是对齐问题。而结构体所占用的内存空间就是每个成员对齐后存放时所占用的字节数之和。

计算机系统对基本数据类型的数据在内存中存放的限制是:这些数据的起始地址的值要求是某个数K的倍数,这就是内存对齐,而这个数 K 就是该数据类型的对齐模数(alignment modulus)。这样做的目的是为了简化处理器与内存之间传输系统的设计,并且能提升读取数据的速度。

结构体对齐不仅包括其各成员的内存对齐(即相对结构体的起始位置),还包括结构体的总长度。

2)结构体大小的计算方法和步骤

i. 将结构体内所有数据成员的长度值相加,记为 sum_a ;

ii. 将各数据成员为了内存对齐,按各自对齐模数而填充的字节数累加到sum_a上,记为sum_b。

对齐模数是 #pragma pack 指定的数值与该数据成员自身长度相比较得到的数值较小者。该数据相对起始位置应该是对齐模数的整数倍。

iii. 将和 sum_b 向结构体模数对齐。

该模数则是 #pragma pack 指定的数值与结构体内最大的基本数据类型成员长度相比较得到的数值较小者。结构体的长度应该是该模数的整数倍。

数据类型自身对齐:

所谓“对齐在N上”,是指“存放的起始位置是%N = 0”.

总结

到此这篇关于C语言结构体(struct)的文章就介绍到这了,更多相关C语言结构体struct内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!

推荐阅读

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    探探语言设置|探探怎么设置语言

    探探语言设置|探探怎么设置语言,,1. 探探怎么设置语言打开探探软件,然后就有消息提示的红点,点开就行了!其实这些软件都是挺简单的操作的,都是

    git设置编码|git语言设置

    git设置编码|git语言设置,,git设置编码点击cap4j搜索从git直接链接上拉代码。git语言设置Git是一个开源的分布式版本控制系统,可以有效、高

    论竞技比赛结构中的十种常见误区

    论竞技比赛结构中的十种常见误区,,近年来,在中国电子竞技的发展得到了迅速的发展。虽然网络游戏市场正在进一步扩大,但我们也看到CS和魔兽争

    区域语言设置|区域语言设置工具

    区域语言设置|区域语言设置工具,,区域语言设置工具你好,大致的方法如下,可以参考:1、按下键盘的windows 图标,再开始菜单中单击“设置”;出现的

    c4d语言设置|c4d汉语设置

    c4d语言设置|c4d汉语设置,,1. c4d汉语设置mac版的C4D是这样的,中文字体是有的,但是是以拼音的形式存在,比如黑体就是ht。中文字体以拼音方式

    电脑宣传语|电脑宣传语言

    电脑宣传语|电脑宣传语言,,1. 电脑宣传语言1.我做好了与你过一辈子的打算,也做好了你随时要走的准备,2.每段青春都会苍老,但我希望记忆里的你

    office语言设置|微软office语言设置

    office语言设置|微软office语言设置,,微软office语言设置一、首先点击桌面左下角“WIN键”。二、弹出选项内点击“所有程序”。三、接着点

    小米设置日语|小米设置日语语言

    小米设置日语|小米设置日语语言,,1. 小米设置日语语言MIUI系统文字目前只支持简体中文、繁体中文、英文、藏文和维吾尔文,不支持日文 2. 小