结构体基础:
结构是一些值的集合,这些值被称作是成员之间的变量。结构体 每个成员可以是不同类型变量。
好,那我就先举个代码例子,让大家更容易去了解什么是结构体:
#include<stdio.h> //描述一个学生 typedef struct student { char name[20];//学生名字 char sex[5];//学生性别 char id[20];//学生学号 short int age;//学生年龄 }student;//注意:对结构体类型进行重命名 int main(void) { student mation = { "小明", "男", "123456789", 18 };//typedef命名的新名字student printf("%s\n", mation.name); printf("%s\n", mation.sex); printf("%s\n", mation.id); printf("%d\n", mation.age); return 0; }
struct — 结构体的关键字。
student — 结构体的标签,可以随意的替换看你指向的对象是谁了。
struct student —— 叫做结构体类型。
大括号 { } 里面的内容被称作是:成员变量, 注意大括号后面必须要有分号,可以加成员列表,分号前面内容,可以是全局的结构体变量(一般都不会去使用),在代码中我们要尽可能的去少的使用全局变量。
在函数中 mation —— 结构体类型的变量,当然这里我直接 student mation;是可以的,因为我用了typedef关键字,当然这个是可以随意定义结构体标签新的名字,不过我喜欢直接去定义结构体标签。
结构体类型的变量(mation)需要存放结构体类型的成员变量,所以我们可以要给上一个大括号直接去接收这些结构体变量,到了这一步,我们的结构体类型的初始化已经🆗了。注意:结构体类型的成员变量的数据类型使用不要弄错了以及主函数当中的打印的占位符记得要和全局变量一一对应才行。
最后,就是打印了。这里说下xxx.xxx在这个解释下什么意思:xxx.这个是结构体标签,通过这个后面的xxx是结构体当中类型的成员变量,也就是找到那个成员。
以上我讲的这一步骤,是定义:结构体的类型。那么在这里细心的朋友已经发现了,代码中结构体类型前面还加了一个typedef,那在这里我跟大家说下:typedef把结构体类型给重新的起了一个名字,在主函数中大家就可以知道。而,分号前我也写了注释。
typedef作用:
想了想,还是把typedef单独拿出来说一说吧
C 语言提供了 typedef 关键字,你可以使用它来为类型取一个新的名字。
typedef struct Books == Book book 就像这样.
看到这里可能有些人会感觉和#deifne怎么感觉一样,那在这里我说下:
#define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:
typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
结构体的作用:
结构体和其他类型基础数据类型一样,例如 int 类型,char 类型 只不过结构体可以做成你想要的数据类型。以方便日后的使用。
在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。
结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。
结构体的大小与内存对齐:
结构体的大小不是结构体元素单纯相加就行的,因为我们现在主流的计算机使用的都是 32Bit 字长的 CPU,对这类型的 CPU 取 4 个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素是就会相对更高效,这就是内存对齐的由来。
结构体成员的类型
结构体成员的类型,可以是变量,数组,指针,甚至是其它的结构体,这里就不每个去列举了。
结构体成员
结构体变量的访问成员,是通过操作符(.)访问的。
结构体(套娃‘doge’)
在结构体成员类型中我说了下,但有些小伙伴可能会有点不清楚,在这里我把代码给大家,注意: 在上面结构体我使用了红色字体所标注的.
#include<stdio.h> //学生家地址 struct address { char T [20]; }; //描述一个学生 typedef struct student //typedef —— 可以使用它来为类型取一个新的名字 { char name[20]; //学生名字 char sex[5]; //学生性别 char id[20]; //学生学号 short int age; //学生年龄 struct address S; }student; //注意:对结构体类型进行重命名 int main(void) { // struct student mation;// mation —— 结构体类型的变量 student mation = { "法外狂徒张三", "man", "10086", 18, {"康达小区三懂一单元"} }; printf("%s\n", mation.name); printf("%s\n", mation.sex); printf("%s\n", mation.id); printf("%d\n", mation.age); printf("%s\n", mation.S.T);//注意,由于我们是把一个结构体类型放在另一个结构体,所以这里需要找两次。 return 0; }
结构体传参和传值
1.传参
注意,在print函数当中记得定义结构体关键字。
#include<stdio.h> //描述一个学生 typedef struct student //typedef —— 可以使用它来为类型取一个新的名字 { char name[20]; //学生名字 char sex[5]; //学生性别 char id[20]; //学生学号 short int age; //学生年龄 }student; //注意:对结构体类型进行重命名 void print(student tmp) { printf("%s\n", tmp.name); printf("%s\n", tmp.sex); printf("%s\n", tmp.id); printf("%d\n", tmp.age); } int main(void) { // struct student mation;// mation —— 结构体类型的变量 student mation = { "法外狂徒张三", "man", "10086", 18 }; //实现传参 print(mation); return 0; }
2.传址
注意:print2函数中打印的,-> (操作符)。在这里tmp2指针箭头指向对象的内容。
#include<stdio.h> //描述一个学生 typedef struct student //typedef —— 可以使用它来为类型取一个新的名字 { char name[20]; //学生名字 char sex[5]; //学生性别 char id[20]; //学生学号 short int age; //学生年龄 }student; //注意:对结构体类型进行重命名 void print2(student *tmp) { printf("%s\n", tmp->name); printf("%s\n", tmp->sex); printf("%s\n", tmp->id); printf("%d\n", tmp->age); } int main(void) { // struct student mation;// mation —— 结构体类型的变量 student mation = { "法外狂徒张三", "man", "10086", 18 }; //实现传址 print2(&mation); return 0; }
各位,这两个函数如果要选择一个的话,选择第2个。因为:
传参:如果当我们用实参传递给形参的话,其实就是一份临时拷贝。这样的话就要把所有的数据内存空间给再copy一份下去。放在其它的内存上,在这里我取名为tmp。就很简单就是例如,是200个字节那么你传的参数就也要两百个字节,这就会导致空间的一个浪费就会非常严重滴,同时你copy过去还需要一定的时间。
传址:这里我传过去的仅仅是地址(&),一个地址就是4字节(32位)8个字节(64位),注意这里是int类型的数据类型所以是4个字节以及32个比特位,用三十二位的二进制来进行表达。
如果要选择一种,我们尽可能的去选择传址,因为效率更高些,而且还可以省出一定内存空间,尤其是对大型项目的看法,两种我们就可以去选择传址。
结论:当结构体传参的时候要传入结构体的地址。