(萌新笔记)C语言的复习笔记(3)

初始时间:大一(上) 12月

更新时间:大一(上) 12月

大学生/初学者/弱鸡 因此本文可能会有很多基本知识,还请大家斟酌观看

PS:本文仅供有些C语言基础,想回顾知识点的伙伴阅读

Start!(੭•̀ω•́)੭ ̸*✩⁺˚(施法ing
———————————————————————————————————————————————————

一、内存池

我们常常用malloc()和free()申请和释放堆内存,但频繁的调用它们容易产生大量的内存碎片,如下图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
比如我们先申请了一块12KB的内存块A,紧接着又申请了挨着存放的16KB内存块B,这时如果使用free()释放了内存块A,那么这时空出来的就是内存碎片,下次只有申请同样大小(12KB)的内存空间时,才能 "填补"内存碎片,若下次申请的是16KB的内存空间,就可能出现额外占用其他空间,使得之前空出来的内存碎片无法重复利用,导致内存浪费

而且频繁申请、释放内存空间是非常浪费时间的,因为调用malloc()向操作系统申请堆内存,程序要经历从应用层切入到系统内核层的过程,分配完成后再切回程序的应用层
在这里插入图片描述
此时,我们就可以使用内存池了,具体编程是使用一个单链表维护一个简单的内存池,即需要将没有用的内存空间地址依次用一个单链表记录下来,当再次需要的时候,从这个单链表中获取即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体实现内存池可以参考我的另一篇博客:通讯录管理系统(主体是单链表)

二、typedef

前提:下面是 typedef 的普通用法:

typedef int interger;//即给 int 起了个别名 interger
interger a = 1//定义整型 a 并赋值为 1

① typedef 与 结构体

有关于 结构体的 typedef 用法,大家可以去这篇博客参考

② typedef 与 define(宏定义)

#define interger int;

unsign interger a;
a = -1;
printf("a = %u\n",a);
output: a = 4294967295

由于 -1 被转换为无符号整型,所以输出为 4294967295

将 #define interger int 换成 typedef int interger
output: error

程序出现报错,这是因为 define 是机械式替换, typedef 是对类型的封装,不理解的话再看下一个例子

typedef int* pint

int a = 5;
int b = 6;
pint p1, p2;
p1 = &a;
p2 = &b;
printf("%d %d", *p1, *p2);
output: 5 6
typedef int* pint 换成 #define pint int*
output:[Error] invalid conversion from 'int*' to 'int' [-fpermissive]

意思是 p2 是 int 型数值,并不是指针,这是因为 define 是机械式替换, typedef 是对类型的封装

③ typedef 与 define(宏定义)与 const

底层 const 是表示指针所指的对象是一个常量(*p)

顶层 const 是表示指针本身是个常量(p)

#define ps char*;
typedef char* pr;	
	
const pr p = NULL;
const ps q = NULL;
*p = 12;//正确,因为 typedef 把 p 的底层 const 变成了顶层 const
*q = 12;//错误,因为 const 的存在

④ typedef 的进阶用法

为复杂的声明语句起别名,如:

int (*p)[3];
typedef int (*PTR)[3]; //起别名为 PTR

int a[3] = {1,2,3};
PTR b = &a;
printf("%d %d %d",*b[0],*b[1],*b[2]);
output: 1 2 3
 这里的 PTR b = &a 相当于 int (*b)[3] = &a

再举一个例子:

void ( *funA (int, void (*funB) (int) ) ) (int)

乍一看是很复杂,但我们可以将其简化成两个分布函数

void ( *funA(参数) ) (int)  funA 就是指针函数

参数 : void ( *funB ) (int)  funB 就是函数指针

那我们遇到这种多项函数有什么更快的区分办法呢?其实用 typedef 就可以了

typedef void ( *PTR ) (void);
PTR funA (int, PTR);

没错,上面两个简单的式子就把复杂函数给简化了,非常的简洁易懂

三、共用体(也称联合体)

① 共用体的声明

与结构体类似,但共用体的所有成员拥有同一个内存地址

union data
{
	int i;
	char ch;
	float f;
};

② 共用体的定义

三种定义方式

单独定义多个共用体变量
union data
{
	int i;
	char ch;
	float f;
};
union data a, b, c;
在声明时同时定义
union data
{
	int i;
	char ch;
	float f;
} a, b, c;
共用体名字不是必需的
union
{
	int i;
	char ch;
	float f;
} a, b, c;

③ 初始化共用体

union data
{
	int i;
	char ch;
	float f;
};

普通初始化
union data a;
a.i = 520;

特殊初始化
union data a = {520};//初始化第一个成员
union data b = a;//直接用一个共用体初始化另一个共用体
union data c = {.ch = 'C'};//C99新特性,指定初始化成员

但是记住:一次只能初始化一个成员值

④ 共用体的打印

#include <stdio.h>
union data
{
	int i;
	char ch;
	float f;
};
int main()
{
	union data c = {.ch = 'C'};
	printf("%c",c.ch);
	return 0;
}

output: C

也记住:一次只能打印一个成员值

若同时打印多个成员值,则会出现

#include <stdio.h>
#include <string.h>
union data
{
	int i;
	float pi;
	char str[6];
};
int main()
{
	union data a = {520};
	a.pi = 3.14;
	strcpy(a.str,"LoveU");
	printf("%d\n%f\n%s",&a.i,&a.pi,a.str);
	return 0;
}

结果如下:
在这里插入图片描述
只有最后一个成员的值的正确的,这是因为三个成员都共用一个内存地址,对它们取值会导致相互覆盖

那么共用体会占用多大的空间呢?

union data
{
	int i;
	float pi;
	char str[10];
} a;

printf("%d",sizeof(a))

output: 12

为什么不是最大的成员尺寸(10)呢?这主要与内存对齐有关,可以参考我写的这篇博客:C语言有关结构体的概念的 第一、4节

四、枚举

#include <stdio.h>
int main()
{
	enum Color { red = 10, green, blue };
	enum Color rgb; //enum 型变量

	for (rgb = red; rgb <= blue; rgb++) //自增
	{
		printf("rgb is %d\n", rgb);
	}
	return 0;
}
output:
rgb is 10
rgb is 11
rgb is 12

注意:enum 型变量的自增(++)仅仅在 VS2019 有效,在 Dev-C++ 中无效

再举个例子(无 enum 型变量)

#include <stdio.h>
int main()
{
	enum Color { red, green = 10, blue };

	printf("red is %d\n", red);
	printf("green is %d\n", green);
	printf("blue is %d\n", blue);
	return 0;
}
red is 0
green is 10
blue is 11

说明 red 初始化是从 0 开始的

五、位域

使用位域的做法是在结构体时,在结构体成员后面使用冒号( : )和数字来表示该成员所占的位数

#include <stdio.h>
int main()
{
	struct Test
	{
		unsigned int a : 1;
		unsigned int b : 1;
		unsigned int c : 2;
	};
	struct Test test;
	test.a = 0;
	test.b = 1;
	test.c = 2;
	printf("a = %d,b = %d,c = %d\n", test.a, test.b, test.c);
	printf("size of test = %d\n", sizeof(test));
	return 0;
}
output:
a = 0,b = 1,c = 2
size of test = 4

冒号后面代表了该成员的位域,可以看出整个 test 结构体只占用了 4 字节的空间(1 + 1 + 2)

有两个规定:
1、该成员的位域不能超过该成员的类型(如 unsigned int 是 4 个字节,即 32 位,位域不能超过32)
2、为该成员赋值的值不能超过改位域(如位域设置为 2,则不能赋值为 4,因为 4 的二进制是 101 ,超过 2 位)

补充:C语言的标准只说明 unsigned int 和 signed int 和 bool 支持位域

本系列 C语言的复习笔记 就到此结束了!中途虽然有开心有无聊但最终还是学完了,也感谢大家看到这里,我们下个系列再见ヾ( ̄▽ ̄)ByeBye

发布了92 篇原创文章 · 获赞 35 · 访问量 6381

猜你喜欢

转载自blog.csdn.net/CourserLi/article/details/103513903
今日推荐