c语言中,我们关注内存中存在的: (除此以外还有其他区)
栈区
局部变量
函数的形式参数(形参)
堆区
malloc/free
calloc
realloc
动态内存分配
静态区
全局变量
静态变量(const)
动态内存管理主要的四个函数
#include <stdlib.h> //动态内存头文件
mallco和free
void* malloc(size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
void free (void* ptr);
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。
int main()
{
int* ptr = (int*)malloc(40); //malloc向堆区申请了40个字节,返回void*类型。我们强制转换为int*类型
int* p = ptr; //确保申请的空间的起始地址不丢失
if (p == NULL)
{
perror("malloc"); //如果开辟失败,则用perror返回错误原因
return 1;
}
//memset(p, 0, 40); //初始化p地址开始的40个字节的空间
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i;
p++;
}//此处为申请的40字节的空间初始化
//用完该空间后不需要,则释放空间 free
free(ptr); //从申请的空间的起始地址 开始释放,所以需要ptr
ptr = NULL; //释放后,ptr成为了野指针,置为 NULL 空指针
return 0;
}
calloc
void* calloc(size_t num, size_t size);
用于申请内存并初始化为0
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
perror("calloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
realloc
void* realloc (void* ptr, size_t size);
调整申请的内存空间的大小
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*(p+i) = i;
}
//当空间不够,希望可以放20个元素,需要realloc扩容
int* ptr = (int*)realloc(p, 80);//整体变成80字节。不是追加80个字节
//此处两种情况
if (ptr != NULL)
{
p = ptr;
}
//扩容成功,开始使用。
//不再使用
free(p);
p = NULL;
return 0;
}
上述的两种情况:
1.如果后续的空间足够扩容,那么就延续p的地址后面的空间进行扩容
p[][][][][][][](后面扩容)[][][][][][][]
2.如果后续的空间不足够扩容,那么它会在内存的其他地方寻找一个足够的空间,并将p的内容转移到新空间后继续扩容,同时将会free释放掉p原本的空间 所以为了防止扩容失败(找不到足够的空间)且释放了原本了空间,进行int* ptr = realloc(p,80); 确保成功后再将ptr赋值给p
常见内存的错误
1.对空指针的解引用
解决办法:对malloc函数返回值进行空指针判定
if (p == NULL)
{
perror("malloc"); //如果开辟失败,则用perror返回错误原因
return 1;
}
2.对动态内存开辟空间的越界访问
3.对非动态开辟内存使用free释放
4.使用free释放一块动态开辟内存的一部分
5.对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
6.动态开辟内存忘记释放(内存泄漏)
经典面试题
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void main(void)
{
char* str = NULL;
GetMemory(str);
if (str == NULL)
{
perror("malloc");
}
strcpy(str, "hello world");
printf(str);
}
运行报错,p是形参。结束后 str依旧是空指针。
错误类型:对空指针的解引用,程序崩溃
修改为正确:
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void main(void)
{
char* str = NULL;
GetMemory(&str);
if (str == NULL)
{
perror("malloc");
}
strcpy(str, "hello world");
printf(str);
}