一.动态内存分配的意义
我们之前学习开辟空间的大小是固定的,一旦开辟了空间大小就不能调整。
int a = 10;
int arr[20]={0};
所以C语言引入了动态内存开辟,让我们自己申请和释放空间。
因此动态内存分配让C语言程序能够在运行时灵活管理内存,平衡了内存使用的效率与灵活性 ,是实现复杂功能(如操作系统、数据库)的基础。
头文件:
#include<stdlib.h>
二.malloc
1.函数原型
void* malloc(size_t size);
//size_t size:申请内存空间的大小,单位是字节。
//void*:返回void*指针类型,注意强制类型转化
(1)如果开辟成功,则返回一个指向开辟好空间的起始地址。(注意强制类型转化,因为有返回值是void*)
(2)如果开辟失败,则返回NULL指针,因此在使用后要检查指针是否为空指针。
2.使用
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(20);//开辟动态内存,p指向首地址
if (p == NULL)//判断是否为空指针
{
perror("malloc");
return 1;
}
//使用空间
int i;
for (i = 0; i < 5; i++)
{
*(p + i) = i + 1;
}
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
三.free
1.函数原型
void free(void* ptr);
//void* ptr:释放内存空间的起始地址
(1)ptr指向空间是动态内存开辟的首地址。
(2)如果ptr是NULL指针,则函数什么是都不做。
2.使用
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(20);//开辟动态内存
if (p == NULL)//判断是否为空指针
{
perror("malloc");
return 1;
}
int i;
for (i = 0; i < 5; i++)//使用动态内存空间
{
*(p + i) = i + 1;
}
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
//释放空间
free(p);//将空间还给操作系统
p = NULL;//防止成为野指针
return 0;
}
3.注意事项
free里面是起始地址
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(20);
if (p == NULL)
{
perror("malloc");
return 1;
}
int i;
for (i = 0; i < 5; i++)
{
*p= i + 1;
p++//此时p不是起始地址
}
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
free(p);//p不是起始地址
p = NULL;
return 0;
}
四.calloc
1.定义
void* calloc(size_t num, size_t size);
//size_t num:成员个数
//size_t size:每个成员大小
与malloc区别:
(1)calloc有2个参数。
(2)calloc将空间的每个字节初始化为0。
2.使用
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)calloc(5, sizeof(int));
//使用malloc:int* p=(int*)malloc(5*sizeof(int));
if (p == NULL)
{
perror("calloc");
return 1;
}
//使用动态内存空间
int i;
for (i = 0; i < 5; i++)
{
*(p + i) = i + 1;
}
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
五.realloc
1.定义
void* realloc(void* ptr, size_t size);
//void* ptr:需要修改动态内存空间的首地址
//size_t size:修改后的内存大小
//void*:返回修改后的内存首地址
注意:调整空间存在3种情况:
(1)原有空间之后有足够大空间:直接在原有内存后追加空间,原来空间的数据不发生变化。
(2)原有空间之后没有足够大空间:
在堆空间的另一个位置找到连续空间来使用,释放旧空间,同时返回一个新的首地址。
(3)调整失败,返回是一个NULL。
因此,我们在调整后,需判断返回的指针是否为NULL。
2.使用
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(5 * sizeof(int));
if(p==NULL)
{
perror("malloc");
return 1;
}
/*
使用动态空间......
*/
//调整空间大小:
int* ptr = (int*)realloc(p, 10 * sizeof(int));//注意不能用p指针来接收,
//后面需判断返回是否为空指针
if (ptr != NULL)
{
p = ptr;
/*
使用动态内存......
*/
free(p);
p = NULL;
}
else
{
perror("realloc");
//ptr指针为空指针,但p指针所指向的内存空间仍可以使用
/*
使用p指针指向的动态内存
*/
free(p);
p = NULL;
}
return 0;
}
3.补充
realloc也可以跟malloc一样创建动态内存空间。
int*p = (int*)realloc(NULL,20);//当地址为空指针时,会自动创建一块动态内存空间
int*p = (int*)malloc(20);
六.动态内存分配的常见错误
1.对NULL指针解引用
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(INT_MAX);//当申请的动态内存太大时可能返回NULL
*p = 20;//没有判断p指针是否为空指针
free(p);
p = NULL;
return 0;
}
总结:申请完动态内存后要判断是否为空指针
2.对动态内存空间的越界访问
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 0;
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
for (i = 0; i <= 10; i++)//当i=10时,动态内存越界访问
{
*(p + i) = i;
}
free(p);
p = NULL;
return 0;
}
总结:注意动态内存大小,不要越界访问
3.对非动态内存空间使用free释放
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 10;
int* p = &a;//p开辟的不是动态内存
free(p);
return 0;
}
总结:注意free释放对象
4.使用free释放一块动态开辟内存的一部分(即free后面跟着的地址不是首地址)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(10*sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i;
p++;//p移动了指向的不是首地址
}
free(p);//释放时p就不是首地址
p = NULL;
return 0;
}
//修改后:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(10*sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
p[i] = i;//移动后p指向的依然是首地址
}
free(p);
p = NULL;
return 0;
}
总结:注意free释放对象
5.对同一块动态内存多次释放
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(100);
free(p);
//......
free(p);//有时可能忘记前面释放了,写了很多代码后又释放了一次
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(100);
free(p);
p = NULL;//将p置为空指针
//......
free(p);
return 0;
}
总结:释放后要及时置NULL
6.忘记对动态内存释放(会导致内存泄露)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(20);
if (p == NULL)
{
perror("malloc");
return 1;
}
//使用动态内存中......
//没有释放动态内存
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 3;
int* p = (int*)malloc(20);
if (i > 0)
{
return;//提前返回,即使后面有释放内存空间的代码,但也执行不到
}
free(p);
p = NULL;
return 0;
}
总结:注意要释放内存同时要执行该代码
————————————————
版权声明:本文为CSDN博主「fffzd」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yyyzc_/article/details/156205328
|
|