初始时间:大一(上) 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 支持位域