结构体中级
结构体嵌套
以变量形式嵌套
以结构体变量为数据成员
- 通常用来做深层次的一个抽象
struct Score {
int english;
int math;
int py;
};
struct Student
{
char name[20];
int age;
int num;
//int score[3];
struct Score stuScore;
};
结构体变量当做函数参数
void printData(struct Student stu)
{
printf("姓名\t年龄\t编号\tmath\tenglish\tpy\n");
printf("%s\t%d\t%d\t%d\t%d\t%d\n", stu.name, stu.age, stu.num,
stu.stuScore.math, stu.stuScore.english, stu.stuScore.py);
}
访问数据方式
-
剥洋葱
struct Student stuData = { "小美",19,1002,{89,89,80}}; printData(stuData); strcpy_s(stuData.name,20, "张三"); stuData.age = 19; stuData.num = 1001; stuData.stuScore.py = 90; stuData.stuScore.english = 89; stuData.stuScore.math = 29; printData(stuData);
直接嵌套————内嵌
struct A
{
int a;
struct B
{
int b;
}bNum; //一般这里会跟一个变量
};
void test()
{
struct A aNum;
aNum.a = 1;
aNum.bNum.b = 2;
struct B bb;
bb.b = 123;
printf("%d\t%d\t%d\n", aNum.a, aNum.bNum.b,bb.b);
}
结构体中的指针
基本的指针
-
指针能够存储字符串或者存储其他数据,一定是要有指向的内存,才可存储
-
所谓的存储东西,就是通过拷贝的方式或者赋值的方式把元素移动到另一个内存上
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /* 1.包含基本的指针 */ //指针能够存储字符串或者存储其他数据,一定是要有指向的内存,才可存储 //所谓的存储东西,通过拷贝的方式或者赋值的方式把元素移动到另一个内存上 struct MAN { char *name; //门卡 int age; }; void initData(struct MAN* pMAN,char* name,int age) { //单纯的发挥指针的指向功能 pMAN->name = name; pMAN->age = age; } //再封装: 内存回收问题 void initDataByName(struct MAN* pMAN) { void printMAN(struct MAN man); char name[20] = "小芳"; initData(pMAN, name, 29); printMAN(*pMAN); } void initData2(struct MAN* pMAN, char* name, int age) { int length = strlen(name) + 1; pMAN->name = (char*)malloc(length); assert(pMAN->name); //拷贝数据到堆内存,相对于来说更为安全一点 strcpy_s(pMAN->name, length, name); pMAN->age = age; } void printMAN(struct MAN man) { printf("%s\t%d\n", man.name, man.age); } int main() { struct MAN man; initData(&man, "小美", 18); printMAN(man); //------------------------- char name[20] = "小芳"; initData(&man, name, 18); printMAN(man); strcpy_s(name, 20, "张三"); printMAN(man); //-------------------------- struct MAN girl; initDataByName(&girl); printMAN(girl); //乱码 //--------------------------- struct MAN boy; initData2(&boy, "张三", 18); printMAN(boy); //---------------------------- free(boy.name); boy.name = NULL; return 0; }
函数指针
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
typedef void (*PRINT)(struct MM* pMM);
struct MM
{
char* name;
int age;
PRINT pPrint;
};
void printMM(struct MM* pMM)
{
printf("%s\t%d\n", pMM->name, pMM->age);
}
struct MM* createMM(char* name, int age)
{
struct MM* mm = (struct MM*)malloc(sizeof(struct MM));
assert(mm);
int length = strlen(name) + 1;
mm->name = (char*)malloc(length);
assert(mm->name);
strcpy_s(mm->name, length, name);
mm->age = age;
//初始化函数
mm->pPrint = printMM;
return mm;
}
int main()
{
struct MM* pMM = createMM("小芳", 18);
printMM(pMM);
pMM->pPrint(pMM);
return 0;
}
结构体自引用
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
struct Node
{
int data;
struct Node* next; //next用来指向struct Node类型的变量的地址就可以
};
int main()
{
//变量的版本的
struct Node a = { 1,NULL };
struct Node b = { 2,NULL };
struct Node c = { 3,NULL };
a.next = &b;
b.next = &c;
//通过指针遍历数据
struct Node* pmove = &a;
printf("a的数据:%d,%p\n", pmove->data, pmove->next);
printf("a的数据:%d,%p\n", (&a)->data, (&a)->next);
while (pmove!=NULL) //等效while(pmove)
{
printf("数据:%d,%p\n", pmove->data, pmove->next);
pmove = pmove->next;
}
return 0;
}
联合体(共用体)
- 充当特殊的标记位,或者开关之类
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
union Flag
{
char a[4]; //存储字符串
int b;
char c; //字符
};
int main()
{
char name[4] = "A";
//每一次只有一个变量有效
union Flag flag = { "A"};
printf("%c\n", flag.c); //使用也需要剥洋葱
printf("%d\n", flag.b);
flag.b = 66;
printf("%c\n", flag.c);
return 0;
}
枚举类型
-
符号整型常量
-
用一个符号替换一个数字
-
默认初始化从0开始
-
一系列的符号替换一系列的数字,避免大量数字/常量(幻数)
#include <stdio.h> //方向 enum Dir {Left,Right,Up,Down}; //left就是0 right就是1 up就是2 down就是3 enum Color {Red=1,White,Blue,BLACK=2,Green}; //2.部分初始化 从前一个已经初始化值依次+1 //Red=1 White=2 Blue=3 BLACK=2 Green=3 enum Element {Wall=1,Blank=0,Box=4,End=3,Role=5,BoxEnd=7,RoleEnd=8}; void printData(enum Element element) { switch (element) { case Wall: break; case Blank: break; case Box: break; } } void printData2(int element) { switch (element) { case Wall: break; case Blank: break; case Box: break; } if (element == Wall) { //.... } } int main() { printf("%d\n", Left); int iNum = Left; printf("%d\n", iNum); printf("%d\n", White); printf("%d\n", BLACK); printData(Wall); printData(1); printData2(Wall); printData2(2); return 0; }
-
特殊结构体——位断
-
位断必须要有长度
#include <stdio.h> #include <stdlib.h> struct Flag { //_ _ unsigned int a : 2; //:后面数字代表当前变量的二进制位数 //a [0,3] unsigned int b : 3; //b [0,7] unsigned int c : 1; //c [0,1] }; //C语言结构体必有成员 //以下错误 //struct MM //{ // //} int main() { struct Flag flag = { 4,5,3 }; printf("%u\t%u\t%u\n", flag.a, flag.b, flag.c); return 0; }
结构体自定义类型的内存问题——字节对齐问题
-
从小往大写
-
字符可以跟正数合在一起
-
字符数组可以任意拆分
-
算出来的内存一般都是:1、2、4、8 这样的倍数
-
位断只有整型
#include <stdio.h> #include <stdlib.h> #include <string.h> struct A { int a; //4 +4 double b; //8 char c; //1 +7 //sizeof(A)=8*3 }; struct B { char c; //1+3 int a; //4+0 double b; //8 //8*2; }; struct C { char c[3]; double b; int a; }; void test() { printf("%d\t%d\n", sizeof(struct A), sizeof(struct B)); printf("%d\n", sizeof(struct C)); } struct D { char c[3]; //3+1 int a; //4 short sa; //2+2 }; struct E { char name[3]; //3 struct D data; //12 //char c[3]; //3+1 //int a; //4 //short sa; //2+2 double d; //8 }; /* char name[6]; //+2 int a; short sa; //+2 double d; */ struct F { char name[5]; int age[3]; //12 /* int a; int b; int c; */ double d; }; void test2() { printf("%d\n", sizeof(struct D)); printf("%d\n", sizeof(struct E)); printf("%d\n", sizeof(struct F)); } union Flag { int age; double a; char name[12]; }; struct Data { unsigned int a : 25; unsigned int b : 12; }; void test3() { //1 4 8 printf("%d\n", sizeof(union Flag)); printf("%d\n", sizeof(struct Data)); } int main() { printf("%d\n", sizeof(long long)); test(); test2(); test3(); return 0; }