C语言基础之结构体中级

结构体中级

结构体嵌套

以变量形式嵌套

以结构体变量为数据成员
  • 通常用来做深层次的一个抽象
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;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想写代码的懒大王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值