我们通常开辟空间的方式
int val =20; //大小为4个字节
char arr[10] ={0} //开辟出一块连续的空间且大小为10
但是上面开辟空间方式的特点
1.空间开辟大小是固定的
2.数组在声明得时候,必须指定数组得长度,它所需要得内存在编译时分配
但是以上的方式不能满足所有情况,有时候我们需要空间的大小在程序运行的时候才能知道,
那数组编译的方式就不能满足了,你那就可以使用动态内存
一.堆区,栈区,静态区
1.栈区:
1)遵循自动分配与释放原则
当函数被调用时,函数内的局部变量,函数的参数灯会在栈上分配空间,函数执行完毕后,这些内存会自动被释放
2)后进先出原则
比如说嵌套函数的时候,内层函数的局部变量会先入栈,当内存函数返回后,其局部变量先出栈,外层函数才能继续执行并访问其自身的局部变量
3)空间有限。如果在栈上分配了过多的内存,可能会导致栈溢出,程序出现错误甚至崩溃
2.堆区
动态分配与释放:堆区的内存分配和释放由程序员手动控制,通过函数malloc,calloc,realloc等函数可以在栈上申请空间,使用完毕后,必须通过free函数释放内存,否则会导致内存泄漏,会一直占用系统资源,知道程序借宿
内存空间较大:堆区的内存空间相对栈区来说要大得多,其大小通常只限于计算机的物理内存和虚拟内存的大小。这使得堆区适用于存储大量的数据或动态生成的数据结构,如数组,链表,树等
分配灵活:
根据程序的实际需求动态申请任意大小的内存块
碎片化问题:
由于堆区的内存分配和释放时动态,经过多次申请和释放后,可能会导致内存碎片化
,内存利用率降低
3.静态区:
全局生命周期:
静态区存储的是全局变量和静态变量,这些变量在程序整个生命周期都有效,直到程序结束
初始化规则
未初始化的全局变量和静态变量会自动初始化为0和空指针,初始化的变量就按照初始化的进行
作用域的限制
全局变量作用域是整个程序,可以在如何函数中访问和修改;而静态局部变量的作用域仅限于定义它的函数内部,但它在函数多次调用后会保持其值不变
二.动态内存函数
1.malloc函数
头文件 #include<stdlib.h>
这个函数向内存申请一块连续可用的空间,并指向这块空间的指针
如果开辟成功,则返回一个指向该块空间的指针
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要检查
返回值为void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由操作者自己决定
函数格式
函数参数的意思:size表示要分配的内存块的大小,单位是字节
void*malloc(size_t size)
2.free函数
头文件 #include<stdlib.h>
free函数用来释放动态开辟的内存
1.如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
2.如果参数ptr是NULL指针,则函数什么事都不做
void free (void* ptr);
malloc函数和free函数使用如下
#include<string.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
//向内存申请空间,且未初始化
int* p = (int*)malloc(20);
//判断空间是否开辟成功
if (p == NULL)
{
//判断错误的原因
//strerror函数是用来判断错误的原有
printf("%s\n", strerror(errno));
return 1;
}
//使用
int i = 0;
for (i = 0; i < 5; i++)
{
//这俩种形式等价
//*(p + i) = i + 1;
//printf("%d ", *(p + i));
//p[i] = i + 1;
//printf("%d ", p[i]);
}
//释放
free(p);
p = NULL;
return 0;
}
注意:
1.把p被free释放后,p仍然指向某一个地址,需要对其设置为空指针,避免出现空指针
2.若malloc函数开辟空间失败,则会返回空指针,所以需要对malloc函数的返回值进行检查
如果malloc函数开辟的空间太大,则会开辟失败
3.calloc函数
头文件:#include<stdio.h>
calloc也是用来开辟动态空间的,但它会把这块空间每个字节初始化为0
参数1:num表示要分配的元素个数,参数2:表示每个元素的大小
void* calloc (size_t num, size_t size);
calloc函数和free函数的使用
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//开辟动态空间
int* p = (int*) calloc(10, sizeof(int));
//判断是否开辟成功
if (p == NULL)
{
printf("%s", strerror(errno));
return 1;
}
//使用
int i = 0;
//进行空间的遍历
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
return 0;
//释放内存
free(p);
p = NULL;
}
程序运行
4.realloc函数
头文件:#include<stdlib.h>
realloc函数开始实现对动态开辟空间大小的调整
格式
参数1:
ptr
是一个指向先前通过malloc
、calloc
或realloc
函数分配的内存块的指针,也就是要调整内存的地址参数2:size表示重新分配后内存块的大小
返回值:realloc函数返回后,返回值为调整之后的空间起始地址
void* realloc (void* ptr, size_t size);
realloc函数的应用
#include<stdio.h>
#include<stdlib.h>
%include<errno.h>
int main()
{
//开辟动态空间
int* p = (int*) calloc(10, sizeof(int));
//判断是否开辟成功
if (p == NULL)
{
printf("%s", strerror(errno));
return 1;
}
//重新分配内存使其能容纳80个字节的空间,成功使用
//realloc函数后,原来由calloc函数开辟的空间会被回收
//所以不需要对p进行释放,如果释放,则会导致程序崩溃
int* pa = realloc(p, 80);
if (pa == NULL)
{
printf("%s", strerror(errno));
return 1;
}
//使用
int i = 0;
for (i = 0; i < 20; i++)
{
*(pa+i) = i + 1;
printf("%d ",*(pa+i));
}
//释放
free(pa);
pa = NULL;
}
程序运行:
realloc在调整内存空间有俩种情况
1.原有空间之后有足够大的空间
2.原有空间之后没有足够大的空间
若为情况1
使用realloc函数后,直接在原有的空间后直接扩展,最终成为一块连续空间,且原有的空间数据不发生变化
若为情况2
原有空间之后没有足够的空间,如果要扩展的话,在原有的堆空间另找一个合适大小的连续空间来使用,这时函数返回的是一个新空间的地址
情况1:在原来的空间直接进行扩展
情况2:没有找到足够的空间,在另一处又开辟了一个空间
三.动态内存中常见的错误
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;
free(p);
}
这段代码有什么问题呢
标签:malloc,函数,管理,int,free,str,动态内存,NULL,语言 From: https://blog.csdn.net/2402_86350741/article/details/143799577