C语言内存管理
一. C程序动态地址空间分布
(1) 空间分布图

(2) Linux环境下验证空间分布图
- 为什么在linux环境下测验?
- 在windows环境下 会存在地址空间布局随机化的保护机制 会导致验证C程序地址空间布局变得困难
#include<stdio.h>
#include<stdlib.h>
int g_val2;
int g_val1 = 10;
int main()
{
//代码区
printf("code addr: %p\n", main);
//字符常量区
const char *str = "hello world!";
printf("read only: %p\n", str);
//已初始化全局数据区
printf("init g_val: %p\n", &g_val1);
//未初始化全局数据区
printf("uninit g_val: %p\n", &g_val2);
printf("static x addr:%p\n", &x);
//堆区
int *p = (int*)malloc(10 * sizeof(int));
printf("heap addr: %p\n", p);
//栈区
printf("stack addr: %p\n", &p);
free(p);
return 0;
}
//代码运行结果
code addr: 0x5fbbd60b81a9
read only: 0x5fbbd60b9016
init g_val: 0x5fbbd60bb010
uninit g_val: 0x5fbbd60bb01c
static x addr:0x5fbbd60bb014
heap addr: 0x5fbc018a36b0
stack addr: 0x7fffdca1f828
- 根据打印出的地址可以看出 符合上面图片中的分布
(3) 补充讲解static
- 为什么static修饰的局部变量的作用域不变 但是生命周期却变成了和全局变量一样在程序结束时才被释放
- 因为static修饰的局部变量在编译时 被分配到了全局数据区 依次它的生命周期和程序一致
二. 动态内存
(1)什么是动态内存
- 在程序运行时 根据需要分配和释放内存
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#define N 10
int main()
{
int* p = (int*)malloc(sizeof(int) * N); //动态开辟空间
if (NULL == p) {
return 1;
}
for (int i = 0; i < N; i++) {
p[i] = i;
}
for (int i = 0; i < N; i++) {
printf("%d ", i);
}
printf("\n");
free(p); //开辟完之后,要程序员自主释放
system("pause");
return 0;
}
(2) 为什么要有动态内存
- 由于栈区空间较小 如果在函数内定义大数组或大数据结构 会导致栈溢出
- 使用动态内存就可以使用空间更大的堆区 从而避免上述问题
int main()
{
char a[1024 * 1024] = { 0 }; //就简单的1M空间,程序就崩溃了
return 0;
}
(3) 野指针
- 野指针就是指针指向的位置是非法的、未定义的或已释放的内存
(4) 常见内存错误及对策
- 结构体成员指针未初始化
/*
struct stu {
const char* name;
int score;
}stu ;
*/
//解决方案
struct stu {
const char* name;
int score;
}stu{"Mike", 10};
int main()
{
strcmp(stu.name, "Tom");
return 0;
}
结构体未初始化 导致stu.name是一个野指针 strcmp尝试访问一个非法地址 导致程序崩溃
- 检测指针的合法性
struct stu {
char* name;
int score;
};
void ShowName(char* name)
{
//所有的指针 如果没有被直接使用 必须设置为NULL(编程规范)
//在函数内部 要验证指针的合法性 本质是验证指针 != NULL
/*
if(name){
}
// 内部条件如果不满足 则中断运行(一般在调试时使用)
assert(name);
*/
printf("%s\n", name);
}
int main()
{
struct stu zhangsan = { NULL, 0 };
zhangsan.name = (char *)malloc(32);
strcpy(zhangsan.name, "Tom");
ShowName(zhangsan.name);
return 0;
}
(5) 内存泄漏
-
内存泄漏是指动态开辟的内存未进行释放
-
内存泄漏几个问题
- 程序退出的时候,曾经的内存泄漏问题还存在吗? 不存在 会强制回收开辟的内存
- 什么样的程序最怕内存泄漏? 永远不会主动退出的程序(操作系统 杀毒软件 服务器程序)
- 内存释放的本质是什么? 本质是解除了动态开辟的空间与指针的关系 空间还是那个空间 只是指针无法在使用了
- 观察free函数的参数,free函数只知道释放空间的起始地址,貌似并不知道要释放多大空间,那如何正确释放呢?
在malloc申请空间时 系统给你的其实更多 多出来的部分 记录这次申请的更详细的信息 free就是通过详细信息知道要释放多大的空间
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *a = (char *)malloc(sizeof(char) * 10);
char *b = (char *)malloc(sizeof(char) * 10);
char *c = (char *)malloc(sizeof(char) * 10);
printf("a addr: %p\n", a);
printf("b addr: %p\n", b);
printf("c addr: %p\n", c);
return 0;
}
//代码运行结果
a addr: 0x5f5a3e6c52a0
b addr: 0x5f5a3e6c52c0
c addr: 0x5f5a3e6c52e0
//可以看出来 我申请的虽然是10个字节 但是a b c之间相差32个字节 多余出来的空间用来存放这次申请更详细的信息
2576

被折叠的 条评论
为什么被折叠?



