创建变量或者数组就是我们常见的内存开辟方式
int num = 100;//开辟4个字节的空间
int arr[10] = {0};//开辟40个字节的连续空间
上面开辟空间的方式有两个特点:
但是很多时候,我们对于空间的需求上面的两种情况是满足不了的,有的时候我们需要的内存大小要程序运行之后才能知道,或者说有时候数组大小空间不够了,那么数组编译时开辟的内存空间的方式就不可行了,这个时候就需要动态内存开辟了。
注意:动态开辟的内存是在堆上的,而我们使用的局部变量和函数的形参是在栈上开辟空间。
malloc和free都声明在 stdlib.h 头文件中
mallo函数是C语言提供的动态内存开辟的函数
这个函数可以想内存申请一块连续可用的空间,并返回指向这块空间的指针.
void* malloc (size_t size);
void*,所以malloc函数并不知道开辟空间的类型,要使用者来决定这块空间用来存放什么size参数给0,这是C语言标准未定义的,取决于编译器的实现C语言还提供了一个和malloc函数成对出现的函数free,用来释放动态开辟的的内存空间
void free (void* ptr);
ptr指向的空间不是动态开辟的,那么对于free函数来说这是为定义的ptr是NULL,则函数什么事都不做代码示例
#include
#include
#include
int main()
{
int arr[10] = { 0 };//在栈区申请了40个字节的空间
int* ptr = (int*)malloc(40);//在堆区申请了40个字节的空间
if (ptr == NULL)
{
//strerror会返回错误信息
printf("开辟内存失败 %s", strerror(errno));
}
else
{
int i = 0;
for (i = 0; i < 10; i++)
{
*(ptr + i) = 0;
}
}
//初始化为0
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}
arr数组是存放在栈区的free函数释放,在程序结束的时候会由系统帮我们自动释放。C语言还提供了一个动态内存分配的函数calloc
void* calloc (size_t num, size_t size);
num个大小为size的元素开辟一块连续的内存空间,并把空间的每一个字节初始化为0malloc的区别只在于calloc会在返回指针之前,把申请空间的每个字节初始化为全0代码示例
#include
#include
#include
int main()
{
int* ptr = calloc(1,sizeof(int));//在堆区申请了4个字节的空间
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
else
{
}
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}

如果我们对申请的内存空间的内容要求初始化,那么可以使用calloc函数
realloc函数则更加灵活,有的时候我们会发现申请的空间太小了有时候又会绝对申请的空间太大了。我们就会对内存的大小进行跳转,而realloc函数就可以对动态开辟内存进行调整。
void* realloc (void* ptr, size_t size);
ptr是要调整内存的起始地址size是调整后的大小realloc对内存大小的调整存在两种情况
所以在使用realloc函数的时候就需要注意
调整空间大小时需要新建一个指针变量来接收返回值,避免内存空间开辟失败。从而导致原理的空间丢失。
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(10);
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
else
{
}
//调整空间
int* p = realloc(ptr, 40);//调整成40个字节大小
if (p == NULL)
{
printf("调整内存空间失败 %s", strerror(errno));
}
else
{
ptr = p;
p = NULL;
}
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}
当开辟内存过大时,ptr是有可能为NULL指针的,当为NULL的时候,*ptr非法访问内存
#include
#include
int main()
{
int* ptr = (int*)malloc(INT_MAX);
*ptr = 100;
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}

越界访问也是会出现问题的
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(12);
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
else
{
int i = 0;
for (i = 0; i < 10; i++)
{
//越界访问
*(ptr + i) = 100;
}
}
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}
使用free是否非动态开辟的内存空间,也是错误的。
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(12);
int arr[10] = { 0 };
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
free(arr);//释放非动态开辟的空间
ptr = NULL;//指向NULL
return 0;
}
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(12);
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
else
{
//此时ptr已经不指向动态开辟内存空间的起始位置了
ptr+=2;
}
free(ptr);//释放空间
ptr = NULL;//指向NULL
return 0;
}
多次释放同一块内存空间也是会有问题的
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(12);
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
else
{
//第一次释放
free(ptr);
}
free(ptr);//再次释放
ptr = NULL;//指向NULL
return 0;
}
只申请不释放,会导致内存泄露,导致那些内存无法被使用。
#include
#include
#include
void test()
{
int* ptr = (int*)malloc(12);
if (ptr == NULL)
{
printf("开辟内存失败 %s", strerror(errno));
}
}
int main()
{
while (1)
{
test();
}
return 0;
}
这是一道非常经典的题目,这段代码存在这一下这个问题
malloc动态开辟的空间未进行释放会造成内存泄露#include
#include
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
return 0;
}
这段代码应该这么修改
malloc函数是从堆上申请空间#include
#include
#include
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
这段代码打印的是啥也不确定
GetMemory函数调用结束了,p数组的声明周期也结束了。#include
#include
#include
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
这道题目典型的内存泄露问题,没有对动态开辟的的内存进行释放
#include
#include
#include
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
int main()
{
Test();
return 0;
}
稍微修改一下就好了
#include
#include
#include
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
if (str == NULL)
{
return;
}
strcpy(str, "hello");
printf(str);
free(str);
str = NULL:
}
int main()
{
Test();
return 0;
}
这道题目最大的问题就是对释放后的动态开辟内存再次使用
#include
#include
#include
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
这段代码写的非常古怪,但还是可以修改的。
#include
#include
#include
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
str = NULL;
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
C/C++程序内存分配的几个区域
malloc就是在堆上开辟空间。