
内存管理认知升维:
在运行程序时,系统将需要的数据都组织存放在内存空间,以备使用。在使用C语言开发软件过程中,常常需要动态地分配和销毁内存空间。
例如,对动态链表中的节点进行插入和删除,就需要对内存进行管理;
(2)内存组织方式,程序在开发完成后,需要先装载到计算机的内核或者半导体内存中,再运行程序;
通常的内存模型体系如下:
2.1 可执行代码区
2.2 常量
2.3 未初始化的变量
2.4 已经初始化的变量
2.5 堆区
2.6 栈区
(3)内存模型可以总结为4个逻辑阶段
3.1 可执行代码
3.2 静态数据。给可执行代码和静态数据分配固定的存储位置。
3.3 堆(动态数据),程序请求动态分配的内存来自内存池
3.4 栈。局部数据对象,函数的参数以及调用函数和被调用函数的联系放在称为"栈"的内存池中;
根据操作平台和编译器的不同,堆和栈既可以是被所有同时运行的程序共享的操作系统资源,也可以是使用程序独占的局部资源;
(4)堆与栈
通过内存组织方式可以看到,堆用来存放动态分配内存空间,而栈用来存放局部数据对象,函数的参数以及调用函数和被调用函数的联系;
4.1 堆,在内存的全局存储空间中,用于程序动态分配和释放的内存块称为"自由存储空间",通常也称之为"堆";
在C程序中,使用malloc()和free()函数来从堆中动态分配和释放内存。
4.2 栈,程序不会像处理堆那样的栈中显示地分配内存。当程序调用函数和声明局部变量时,系统间自动分配内存;
栈是一个"后进先出"的压入弹出式的数据结构体,后进先出是栈明显区别于堆的标志。
- #include
- #include
-
- /*
- 内存管理认知升维:
- 在运行程序时,系统将需要的数据都组织存放在内存空间,以备使用。在使用C语言开发软件过程中,常常需要动态地分配和销毁内存空间。
- 例如,对动态链表中的节点进行插入和删除,就需要对内存进行管理;
- (2)内存组织方式,程序在开发完成后,需要先装载到计算机的内核或者半导体内存中,再运行程序;
- 通常的内存模型体系如下:
- 2.1 可执行代码区
- 2.2 常量
- 2.3 未初始化的变量
- 2.4 已经初始化的变量
- 2.5 堆区
- 2.6 栈区
- (3)内存模型可以总结为4个逻辑阶段
- 3.1 可执行代码
- 3.2 静态数据。给可执行代码和静态数据分配固定的存储位置。
- 3.3 堆(动态数据),程序请求动态分配的内存来自内存池
- 3.4 栈。局部数据对象,函数的参数以及调用函数和被调用函数的联系放在称为"栈"的内存池中;
- 根据操作平台和编译器的不同,堆和栈既可以是被所有同时运行的程序共享的操作系统资源,也可以是使用程序独占的局部资源;
- (4)堆与栈
- 通过内存组织方式可以看到,堆用来存放动态分配内存空间,而栈用来存放局部数据对象,函数的参数以及调用函数和被调用函数的联系;
- 4.1 堆,在内存的全局存储空间中,用于程序动态分配和释放的内存块称为"自由存储空间",通常也称之为"堆";
- 在C程序中,使用malloc()和free()函数来从堆中动态分配和释放内存。
- 4.2 栈,程序不会像处理堆那样的栈中显示地分配内存。当程序调用函数和声明局部变量时,系统间自动分配内存;
- 栈是一个"后进先出"的压入弹出式的数据结构体,后进先出是栈明显区别于堆的标志。
- */
- int main() {
- char* pInt; // 定义字符型的指针变量
- pInt = (char*)malloc(sizeof(char)); // 动态给pInt变量分配内存;
- // 使用分配的内存
- *pInt = 65; // 给变量赋值
- printf("the graph is : %c\n", *pInt); // 输出显示图形
- free(pInt); // 释放pInt变量所占用的内存
- return 0;
- }
运行效果:
the graph is : A
D:\program_file\C++_workspace\ProjectToMemoryDynamicManager\x64\Debug\ProjectToMemoryDynamicManager.exe (进程 9316)已退 出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
内存的动态管理
(1)malloc()函数原型如下:
void *malloc(unsigned int size);
在stdlib.h头文件中包含函数,作用是在内存中动态分配一块size大小的内存空间。malloc()函数会返回一个指针;
该指针指向分配的内存空间,如果出现错误,则返回NULL;
(2)使用malloc()函数分配的内存空间在堆中,而不是在栈中,因此在使用万这块内存空间之后一定要将其释放掉,释放内存空间使用的是free()函数;
(3)C语言规定,如果所申请的内存空间分配不成功,malloc()函数的返回值为null pointer,也即是NULL。在这种情况下,如果进行执行之后的代码,程序就会产生崩溃。
所以在申请分配内存空间后,都应该及时检测内存空间分配是否成功;
- #include
- #include
-
- /*
- 内存的动态管理
- (1)malloc()函数原型如下:
- void *malloc(unsigned int size);
- 在stdlib.h头文件中包含函数,作用是在内存中动态分配一块size大小的内存空间。malloc()函数会返回一个指针;
- 该指针指向分配的内存空间,如果出现错误,则返回NULL;
- (2)使用malloc()函数分配的内存空间在堆中,而不是在栈中,因此在使用万这块内存空间之后一定要将其释放掉,释放内存空间使用的是free()函数;
- (3)C语言规定,如果所申请的内存空间分配不成功,malloc()函数的返回值为null pointer,也即是NULL。在这种情况下,如果进行执行之后的代码,程序就会产生崩溃。
- 所以在申请分配内存空间后,都应该及时检测内存空间分配是否成功;
- */
-
- int main() {
- int* iIntMalloc = (int*)malloc(sizeof(int)); // 给指针变量分配内存空间;
- // 使用内存空间
- if (iIntMalloc != NULL) {
- *iIntMalloc = 102400; // 使用该内存空间保存数据
- printf("衣服有%d件\n", *iIntMalloc); // 输出数据
- }
- else {
- printf("为iIntMalloc指针申请内存空间异常");
- }
-
- return 0;
- }
运行效果:
衣服有102400件
D:\program_file\C++_workspace\ProjectToMemoryDynamicManagerFree\x64\Debug\ProjectToMemoryDynamicManagerFree.exe (进程 10252)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
calloc()函数的原型如下:
void *calloc(unsigned n,unsigned size);
使用该函数也要包括头文件stdlib.h,其功能是在内存中动态分配n个长度为size的连续内存空间组。
call()函数会返回一个指针,该指针指向动态分配的连续的内存空间地址。当分配内存空间发送错误时,返回NULL.
- #define _CRT_SECURE_NO_WARNINGS
- #include
- #include
- #include
-
- /*
- calloc()函数的原型如下:
- void *calloc(unsigned n,unsigned size);
- 使用该函数也要包括头文件stdlib.h,其功能是在内存中动态分配n个长度为size的连续内存空间组。
- call()函数会返回一个指针,该指针指向动态分配的连续的内存空间地址。当分配内存空间发送错误时,返回NULL.
-
- */
- int main() {
- char* ch; // 定义指针
- ch = (char*)calloc(30, sizeof(char)); // 分配内存空间
- if (ch != NULL) {
- strcpy(ch, "中国魔都北京总舵"); // 复制字符串
- printf("%s\n", ch);
- free(ch); // 释放内存空间
- }
- else {
- printf("申请内存空间资源异常!");
- }
- return 0;
- }
-
运行效果:
中国魔都北京总舵
D:\program_file\C++_workspace\ProjectToCallocFunctionMemory\x64\Debug\ProjectToCallocFunctionMemory.exe (进程 14932)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
realloc()函数重新分配内存:
原型如下:
void *realloc(void *ptr,size_t size);使用该函数同样要包含头文件stdlib.h,其功能是改变ptr指针指向的内存空间大小为
size字节。设定的size大小可以是任意的,也就是说既可以是原来的数组大,也可以比原来的数值小。返回值是一个指向新地址的指针,
如果出现错误,则返回NULL;
- #include
- #include
- /*
- realloc()函数重新分配内存:
- 原型如下:
- void *realloc(void *ptr,size_t size);使用该函数同样要包含头文件stdlib.h,其功能是改变ptr指针指向的内存空间大小为
- size字节。设定的size大小可以是任意的,也就是说既可以是原来的数组大,也可以比原来的数值小。返回值是一个指向新地址的指针,
- 如果出现错误,则返回NULL;
- */
- int main() {
-
- int *fDouble; // 定义整形指针
- char* iInt;
- fDouble = (int*)malloc(sizeof(int)); // 给指针变量分配整形的内存空间
- printf("%d\n", sizeof(*fDouble));// 输出内存空间的大小
- iInt = (char*)realloc(fDouble, sizeof(char)); // 使用该函数该内存空间的大小
- printf("%d\n", sizeof(*iInt)); //输出内存空间大小
- return 0;
- }
运行效果:
4
1D:\program_file\C++_workspace\ProjectToReallocMemoryFunction\x64\Debug\ProjectToReallocMemoryFunction.exe (进程 18748)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
free()函数的原型如下:
(1)void free(void *ptr);
free()函数的功能是释放由指针ptr指向的内存空间,使部分内存空间能被其他变量使用。ptr是最近一次调用
callo()或malloc()函数时返回的值。free()函数是释放函数。因此必须与分配函数搭配起使用。free()函数无返回值;
(2)申请内存空间之后,响应内存空间使用完毕后应该及时释放,否则可能存在所谓"内存泄露"。所以通常在使用分配内存
空间函数之后,要使用free()函数释放内存空间;
- #include
- #include
- #include
- /*
- free()函数的原型如下:
- (1)void free(void *ptr);
- free()函数的功能是释放由指针ptr指向的内存空间,使部分内存空间能被其他变量使用。ptr是最近一次调用
- callo()或malloc()函数时返回的值。free()函数是释放函数。因此必须与分配函数搭配起使用。free()函数无返回值;
- (2)申请内存空间之后,响应内存空间使用完毕后应该及时释放,否则可能存在所谓"内存泄露"。所以通常在使用分配内存
- 空间函数之后,要使用free()函数释放内存空间;
-
- */
- int main() {
- int* pInt; // 整数指针
- pInt = (int*)malloc(sizeof(int)); // 分配int类型的变量所占的内存空间
- // 使用内存空间,来存储变量
- (*pInt) = 1000;
- // 将数值进行输出
- printf("%d\n", *pInt);
- // free 释放内存
- free(pInt);
- // 将值进行输出
- printf("%d\n",*pInt);
- }
运行效果:
1000
-572662307D:\program_file\C++_workspace\ProjectToFreeMemoryTool\x64\Debug\ProjectToFreeMemoryTool.exe (进程 10024)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
内存丢失认知升维
(1)内存丢失现象
不进行内存释放会造成"内存泄露",从而会导致系统崩溃;
(2)内存丢失的原因
如果不使用free()函数,那么程序可能需要使用100GB内存。这其中包括绝大部分的虚拟内存,而由于虚拟内存的操作需要读写磁盘,
这样会极大地影响到系统的性能,程序因此可能崩溃;
例如:
pOld = (int*)malloc(sizeof(int));
pNew = (int*)malloc(sizeof(int));
这两行代码分别表示创建了一块内存空间,并且将内存空间的地址分别传给pOld和
pNew,此时指针pOld和pNew分别指向两块内存空间。如果进行这样的操作;
pOld = pNew;
pOld指针就指向了pNew指向的内存空间地址,这时再进行释放内存操作;
free(pOld);
此时释放pOld所指向的内存空间是原来pNew指向的,于是这块内存空间被释放了,但是pOld原来指向的那块内存空间还没有被释放,不过
因为没有指针指向这块内存空间,所有这块内存空间就造成了丢失。
(3)内存丢失的解决方案
在程序中编写malloc()函数分配内存空间时,都对应地写出一个free()函数进行释放,这是一个良好的编程习惯。这不但体现在处理大型程序时的必要性,
也在一定程度上体现程序优美的风格和健壮性;