🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 结构体 * 结构体中的属性长度会被自动补齐,这是为了方便指针位移运算 * 结构体中不能定义函数,可以定义函数指针 * 程序运行时,函数也是保存在内存中的,也有一个地址 * 结构体中只能定义变量 * 函数指针其实也是变量,它是指针变量 * 函数指针的定义 返回值类型(*变量名)(接收的参数); * 函数指针的赋值: 函数指针只能指向跟它返回值和接收的参数相同的函数 代码 ``` #include<stdio.h> #include<stdlib.h> /** c结构体 类似java的class struct来声明c的结构体 结构体的大小大于等于结构体中每一变量的占字节数的和 结构体的大小是最大的那个变量所占字节数的整数倍,实际上是将不同类型的成员对齐后再相加 C结构体中不能定义函数,但是通过函数指针也可以解决问题,函数指针指向具体的函数,调用时通过结构体调用函数指针,就可以实现在结构体中拥有函数的需求 函数指针的定义 返回值(*函数指针变量名字)(返回值); -> 间接引用运算符,指向结构体成员运算符,类似于结构成员运算符".";都是用来访问结构体成员的, 只不过使用对象不同,用指针来访问结构体成员,就要用"->"; 假如使用结构体变量来访问结构体成员,就需要结构体成员运算符"." */ void study(){ printf("good good study!\n"); } typedef struct Student{ int age; //8 int score; // 4 char sex; //1 void(*studypointer)();//函数指针studypointer } stud;//typedef为结构体取个别名stud它的作用和struct Student相同,也可以说是简化为stud main(){ stud stu = {18,100,'f'}; stu.studypointer = &study; stu.studypointer(); struct Student* stuPointer = &stu;//结构体指针 struct Student* (类型后面加上“*”符号) printf("*stuPointer.age = %d\n",(*stuPointer).age); (*stuPointer).sex ='m'; printf("stu.sex = %c\n",stu.sex); printf("stuPointer->age = %d\n",stuPointer->age); //printf("stu.age = %hd\n",stu.age); //printf("stu.score = %d\n",stu.score); //printf("stu.sex = %c\n",stu.sex); // printf("结构体student占%d个字节\n",sizeof(stu)); system("pause"); } ``` 输出结果 ~~~ good good study! *stuPointer.age = 18 stu.sex = m stuPointer->age = 18 ~~~ #### 零起点学通C语言摘要 #### **结构体,顾名思义就是多个变量共用一块内存,其实就是用户自定义的数据类型,这个数据类型通常由多个类型的数据成员组成** ``` #include <stdio.h> int main() { struct book //图书 struct是关键字 { int num; //编号 char name[20]; //书名 float price; //价格 int amount; //数量 }; return 0; } ``` **结构变量** struct book Jack ,struct是关键字,用来说明这是一个结构体类型,而book则说明该结构体类型的名字为book,Jack是通过book定义的结构变量,Jack必须通过点运算符访问它的各个成员,然后利用它的成员来保存数据,“.”成为点运算符或者结构成员运算符,优先级高于赋值运算符 **结构变量的多种定义方式** ``` #include <stdio.h> #include <string.h> //一、先声明结构体类型再定义变量。 //先声明结构体类型: struct employees //员工 { char name[20]; //姓名 float pay; //工资 }; //再定义结构变量: struct employees Jane; //也可以一次性定义多个结构变量,每两个结构变量之间用逗号隔开: struct employees John,Rose,Mick; //该语句一次性定义了3个结构变量--John、Rose和Mick。 int main() { //二、声明结构体类型的同时定义变量。 struct employees_a //员工 { char name[20]; //姓名 float pay; //工资 } Jame,Tom,Kity; //右大括号的后面是定义的变量,可以定义一个, //也可以定义多个,假如定义多个,用逗号将它们隔开。 //以下为结构变量赋值 strcpy(Jame.name,"Jack"); //姓名为Jack Jame.pay=3278.60f; //工资为3278.60 strcpy(Tom.name,"Tom"); //姓名为Tom Tom.pay=3578.60f; //工资为3578.60 strcpy(Kity.name,"Kity"); //姓名为Kity Kity.pay=3978.60f; //工资为3978.60 //三、省略结构体类型的名称。 /* struct //员工 { char name[20]; //姓名 float pay; //工资 }LiMing,Liu,Cheng; //struct后面可省略掉结构体的名称。 //以下为结构变量赋值 strcpy(LiMing.name,"Jack"); //姓名为LiMing LiMing.pay=3278.60f; //工资为3278.60 strcpy(Liu.name,"Liu"); //姓名为Liu Liu.pay=3578.60f; //工资为3578.60 strcpy(Cheng.name,"Cheng"); //姓名为Cheng Cheng.pay=3978.60f; //工资为3978.60 */ return 0; } ``` **结构变量的初始化** ``` /*单行初始化 #include <stdio.h> struct //员工 { char name[20];//姓名 float pay; //工资 } one={"李磊",3452.86f},two={"赵安",4562.50f};//可以直接对这2个结构变量进行初始化 int main() { printf("%s的工资为:%.2f\n",one.name,one.pay); printf("%s的工资为:%.2f\n",two.name,two.pay); return 0; } */ //分行初始化 结构变量很多,则需要给结构体类型取个名字,然后在定义结构变量的时候进行初始化 #include <stdio.h> struct employees //员工 { char name[20]; //姓名 float pay; //工资 }; int main() { struct employees LiLei={"李磊",3452.86f};//定义LiLei的时候进行初始化 struct employees ZhaoAn={"赵安",4562.50f}; printf("%s的工资为:%.2f\n",LiLei.name,LiLei.pay); printf("%s的工资为:%.2f\n",ZhaoAn.name,ZhaoAn.pay); return 0; } ``` **结构变量的赋值** ``` #include <stdio.h> struct employees //员工 { char name[20]; //姓名 float pay; //工资 }; int main() { struct employees ZhaoAn={"李磊",3452.86f}; struct employees LiLei={"赵安",4562.50f};//初始化的时候出错,数据保存ZhaoAn和LiLei的数据保存错误 struct employees three;//定义第三个结构体暴力,用于交换ZhaoAn和LiLei的值 three=ZhaoAn; ZhaoAn=LiLei; LiLei=three; printf("%s的工资为:%.2f\n",ZhaoAn.name,ZhaoAn.pay); printf("%s的工资为:%.2f\n",LiLei.name,LiLei.pay); return 0; } ``` **结构体数组** 由多个结构变量组成的数组叫做结构体数组 ``` #include <stdio.h> #define N 10 struct employees //员工 { char name[20]; //姓名 float pay; //工资 }; int main() { struct employees em[N];//利用结构体类型employees定义一个结构体数组em,它有N个元素,每个元素都是一个结构体变量 int i; for (i=0;i<N;i++) { printf("请输入第%d名员工的姓名:",i+1); scanf("%s",&em[i].name);//访问结构体中的元素通过下标 printf("请输入第%d名员工的工资:",i+1); scanf("%f",&em[i].pay); } printf("列出所有员工的工资\n"); for (i=0;i<N;i++) { printf("%s的工资为:%.2f\n",em[i].name,em[i].pay); } return 0; } ``` **结构体的嵌套** 一个结构体变量可以嵌套在另一个结构体中 ``` #include <stdio.h> struct date //日期 { int year; //年 int month; //月 int day; //日 }; struct employees //员工 { char name[20]; //姓名 float pay; //工资 struct date joinDate; //参加工作时间 }; int main() { struct employees em; //创建一个员工em em.joinDate.year=1978; //该员工1978年参加工作 em.joinDate.month=12; //参加工作的月份是12 em.joinDate.day=30; //参加工作的日期是30 return 0; } ``` **结构体的大小** **对齐规则,结构体中最大成员的字节必须是其它成员的整数倍,假如不够则补齐** ~~~ #include<stdio.h> struct stu { int i;//4 char j;//1 float c;//4 }; struct stu1 { char j;//1 int i;//4 double c;//8 }; struct stu2 { char j;//1 int i;//4 double c;//8 char k;//1 }; struct stu3 { char j;//1 int i;//4 double c;//8 char k;//1 char m; char o; char p; char q; char r; char s; char t; }; struct stu4 { char j;//1 int i;//4 double c;//8 char k; char m; char o; char p; char q; char r; char s; char t; char u; }; int main() { struct stu s1={1,'c',198.12f}; int n=sizeof(s1); printf("%d\n",n);//12 printf("%d\n",sizeof(struct stu1));//16 printf("%d\n",sizeof(struct stu2));//24 printf("%d\n",sizeof(struct stu3));//24 printf("%d\n",sizeof(struct stu4));//32 return 0; } ~~~ 输出结果 ~~~ 12 16 24 24 32 ~~~ - **struct stu 中int占用4个字节, char占用1个字节,float占用4个字节,将所有成员都对齐排放,将char与int对齐,这样char也占用4个字节,float同样占用4个字节,这样总共就是12个字节** - **struct stu1中int占用4个字节, char占用1个字节,double则占用8个字节,正好是前面2个成员的整数倍,因此第三个成员占用字节数保持8个不变,将char与int对齐,这样char也占用4个字节,将3个成员所占字节数相加:4+4+8=16** - **struct stu2中int占用4个字节, char占用1个字节,double则占用8个字节,因为第四个成员是char类型,占用1个字节,为了与第三个成员对齐,也给他分配8个字节,假如double后面有8个char型成员,则这8个char型成员将挤在一起。结构体大小为4+4+8+8=24** - **struct stu3 中double后面有8个char型成员,则这8个char型成员将挤在一起,结构体大小为4+4+8+8=24** - **struct stu4 中double后面有9个char型成员,前8个char挤在一起,合占8个字节,第九个char型成员,结构体大小补齐为8则,结构体大小是4+4+8+8+8=32** #### 结构体与指针 #### 可以通过取地址符来获取结构体变量的地址,然后将该地址交给指针来保存,那么只要指针的值不被修改,就可以找到结构体变量 #### 指向结构体变量的指针 ``` #include<stdio.h> #include<string.h> struct book { char name[10]; float price; }; int main() { struct book d1; struct book *p; p=&d1;//取出结构体变量1的地址赋给指针p,现在p指向结构体变量d1 strcpy(p->name,"呼啸山庄");//调用strcpy函数,将"呼啸山庄"复制到指向的结构体变量d1的成员ame中 p->price=11.80f; printf("书名:%s\t价格:%.2f\n",p->name,p->price); return 0; } ``` #### 指向结构体数组的指针 一个指针保存了结构体数组的地址,就可称为指向结构推为数组的指针 ``` #include<stdio.h> #include<string.h> struct book { char name[10]; float price; }; int main() { struct book mybook[3]={ {"呼啸山庄",11.80f}, {"三国演义",46.50f}, {"百年孤独",40.10f} }; struct book *p; int i; p=mybook; /**将结构体数组名复制给指针p,由于数组名即数组的地址, 而数组的地址又是该数组第一个元素的地址,即将第一个结构体变量的地址复制给了指针p */ for (i=0;i<3;i++)//数组mybook共保存了3个结构体变量,因此循环3次 { printf("书名:%s\t价格:%.2f\n",p->name,p->price); p++; } return 0; } ``` >**指向结构体数组的指针每自加一次,是在原有地址的基础上再加上一个元素(结构体变量)所占用的字节数,因此会指向下一个结构体变量**