C语言加强篇——(2)学习笔记 之 结构体、结构体指针、函数指针

系列文章目录

C语言加强篇——(1)学习笔记 之 变量、指针、关键字
C语言加强篇——(2)学习笔记 之 结构体、结构体指针、函数指针
C语言加强篇——(3)学习笔记 之 链表的增、删、改、查



一、结构体

1.什么是结构体

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许存储不同类型的数据项。

为了定义结构,必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;
  1. tag 是结构体标签。
  2. member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
  3. variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
  4. 在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。

关于结构体网上相关的介绍也是比较多的上面介绍参考C结构体 | 菜鸟教程,下面带你了解不一样的结构体。

2.结构体占空间吗?

结构体占空间吗?
要解决这个问题我们先来看什么是结构体,看结构体是怎么定义的:

/*  结构体成员是学生的名字,年龄  */
struct person {
	char * name;
	int age;
}

了解了什么是结构体后,我们我们来对比着学习就知道了。
int、char 等占空间吗?不占空间;int 、char 是变量类型不是变量;变量才分配内存;
那么
struct person 占空间吗?也不占空间;结构体是我们自定义的数据类型不是变量

只有将类型实例化才占内存空间;

那么实例化的结构体占多少内存呢?

struct person zhangsan = {"zhangsan", 22};
/*实例化后的运行结果*/
sizeof(int) = 4, sizeof(char) = 1
sizeof(int *) = 4, sizeof(char *) = 4
sizeof(struct person) = 8
sizeof(struct person *) = 4

struct person 的8个字节怎么来的呢?由该结构体的成员变量决定的。

struct person {
	char * name;  //占 4个字节
	int age;      //占 4个字节
}

看完后是不是感觉原来如此简单?你掌握了吗?我们来看一下下面的结构体:

struct person2 {
	char sex;     //占 1个字节
	int age;      //占 4个字节
}struct person3 {
	char sex;     //占 1个字节
	char high;    //占 1个字节
	int age;      //占 4个字节
}

上面这两个结构体又占多少字节呢??是分别占5个字节、6个字节吗?不是的。

/*实例化后的运行结果*/
sizeof(struct person2) = 8
sizeof(struct person3) = 8

没错这两个结构体都是占8个字节,实际上是:
在struct person2中char sex; 被分配了 4 个字节,sex 用了 1 个字节另外 3 个字节没有用;
在struct person3中char sex; 也被分配了 4 个字节,sex 用了 1 个字节另外 3 个字节没有用;在给char high;分配空间时使用的是 char sex;分配的未使用的空间

如下图:
在这里插入图片描述
那么问题有来了为什么 int age;所占的4字节不从char sex;不用的空间开始往后取4个字节呢?

这就涉及到数据对齐的问题了,CPU为了更快的取指令和数据,一般是成块的取,(比如一次取四字节),这个块一般是2的倍数。如果从奇数地址开始取数,就有可能发生一个数据正好落在两个块里,这样自然就要取两次。所以一般即使数据不够一个块,我们也把下一个数据放到下一个块里,而不是把数据紧密的排在一起。让CPU只取一次就得到需要的数据数是高效率的表现。

学习完以上内容后来看下面一段代码,这段代码是否有问题?问题出现在哪里?

在这里插入图片描述
如果把第35行注释掉是正常的:

在这里插入图片描述
问题就在于,man.a是char型变量占内存1个字节,而指针p 是int型变量占内存4个字节,这时就会出现错误;所以在写程序时一定要注意空间大小问题。

3.结构体成员变量赋值

你知道下面这阳简单的语句执行过程吗?

	a = 123

接下来我们来看一下语句执行过程:
一个芯片内部有CPU、FLASH、RAM等,程序是被下载到FLASH上的,芯片上电后CPU从FLASH中得到指令后,CPU去执行指令;
在这里插入图片描述

FLASH上有指令:a = 123; 要将变量 a 写到内存中,分为以下三步:

  1. 得到 a 的地址
  2. 得到数据值:123
  3. 把数据写入地址对应的空间

由这三步看出语句执行a = 123; 隐含了对地址的操作;那么

	int * p;
	p = &a;
	*p = 123;

这三条语句与a = 123;语句含义相同。

p 是 int 型指针变量;
p 在内存中有空间,可以往空间中写值(这个值是变量 a 的地址),可以使用这个地址来操作变量 a;

整型变量赋值可以通过指针赋值,那么给结构体成员变量赋值呢?

struct person {
	char a;   
	char b;   
	int c;      
}int main(void)
{
	int m;
	struct person man = {'A', 'B', 20};
	
	int *p;                 //int型指针 , 占 4 字节
	struct person *pt;      //结构体指针, 占 4 字节

	m = 123;              //赋值方式1
	p = &m;		//语句1
	*p = 123;	//语句2     赋值方式2(语句1、语句2)
	
}

上面是 int 型变量赋值,是否能够对比写出结构体成员变量赋值呢?
先画个图看一下变量存储情况:
在这里插入图片描述
结构体成员有3个变量,赋值时需要确定是给哪一个变量赋值

/*给结构体成员 c 赋值*/
	man.c = 30;        		 //赋值方式1
	pt = &man;		//语句1
	pt->c = 40;		//语句2     赋值方式2(语句1、语句2)
/*
*	man.c = 30; 	理解为结构体 man 的 c
*	pt->c = 40;     理解为结构体指针 pt 指向的 c
*/

4.结构体应用

#include "stdio.h"


typedef struct student{
	char * name;                //名字
	int age;                    //年龄
	struct student * classmate; //同桌
}student, * pstudent;

int main(void)
{
	student ZhangSan = {"zhangsan", 21, NULL};
	student LiSi = {"lisi", 22, NULL};
	
	ZhangSan.classmate = &LiSi; //张三的同桌是李四
	LiSi.classmate = &ZhangSan; //李四的同桌是张三

	printf("ZhangSan's classmate is : %s\r\n", ZhangSan.classmate->name);

	while(1);
}

二、函数指针

先看代码,看完后你就会发现引入函数指针的便捷。

#include "stdio.h"
#include "string.h"

/*	要求
 *		张三执行动作1
 *		李四执行动作2
 */
 
typedef struct student{
	char * name;                //名字
	int age;                    //年龄
	struct student * classmate; //同桌
}student, * pstudent;

void work1()
{
	/*可编写动作内容*/
}
void work2()
{
	/*可编写动作内容*/
}

int main(void)
{
	int i;
	student ss[2] = {{"zhangsan", 21, NULL},
					{"lisi", 22, NULL}
					};
					
	for(i = 0; i < 2 ; i++)
	{
		if(strcmp(ss[i].name, "zhangsan") == 0)
			work1();
		if(strcmp(ss[i].name, "lisi") == 0)
			work2();
	}
	
	while(1);
}

这是一种写法;如果同学有很多,50个人,100个人呢,这就需要写50个,100个判断语句 ???显然这种写法不是很理想,那么是否还有其他写法呢 ?当然有了

这就要引入函数指针

函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数
函数指针变量的声明:

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

那么结构体就可以重新定义,将执行的动作函数定义为函数指针:

typedef struct student{
	char * name;                //名字
	int age;                    //年龄
	void (* work)(void);		//函数指针
	struct student * classmate; //同桌
}student, * pstudent;

定义的学生结构体数组就可以写成:

	void work1()
	{
		/*可编写动作内容*/
	}
	void work2()
	{
		/*可编写动作内容*/
	}


	student ss[2] = {{"zhangsan", 21, work1, NULL},    //直接将函数名称传进来就行了
					 {"lisi", 22, work2,NULL}
					};


整体写下来就是:

#include "stdio.h"
#include "string.h"

/*	要求
 *		张三执行动作1
 *		李四执行动作2
 */
 
typedef struct student{
	char * name;                //名字
	int age;                    //年龄
	void (* work)(void);		//函数指针
	struct student * classmate; //同桌
}student, * pstudent;

void work1()
{
	/*可编写动作内容*/
}
void work2()
{
	/*可编写动作内容*/
}

int main(void)
{
	int i;
	student ss[2] = {{"zhangsan", 21, work1, NULL},    //直接将函数名称传进来就行了
					 {"lisi", 22, work2,NULL}
					};


	for(i = 0; i < 2 ; i++)
	{
		ss[i].work();   //		ss[0].work();   等价于  work1();
	}
	
	while(1);
}



小结

本文主要讲述结构体、结构体指针、函数指针;针对C语言的学习请持续关注本专栏。

学习百问网资源总结笔记。

本专栏文章:
C语言加强篇——(1)学习笔记 之 变量、指针、关键字
C语言加强篇——(2)学习笔记 之 结构体、结构体指针、函数指针
C语言加强篇——(3)学习笔记 之 链表的增、删、改、查

  • 32
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值