1.为什么存在动态内存分配
动态内存管理是C语言提供给我们自主维护空间大小的能力
C语言提供了一个动态内存开辟的函数:
void* malloc (size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
· 如果开辟成功,则返回一个指向开辟好空间的指针。
· 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
· 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
● 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。
2.动态内存函数的介绍
2.1 malloc
size是要申请的字节数,这个函数最后回返回开辟这个空间的起始地址
内存开辟失败返回空指针
理解内存泄漏的概念:如果开辟一块空间,用完之后没有释放,即没有还给操作系统,其他的变量也用不了这块空间,就相当于这块空间丢了,这种情况就叫做内存泄漏
int main()
{
int arr[10] = { 0 };
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;//返回1说明是异常返回
}
for (int i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (int i = 0; i < 10; i++)
{
pritnf("%d ", *(p + i));
}
free(p);//free释放这块空间存放的东西,但是p指向的地址没有被释放
p = NULL;//让p为空指针
return 0;//返回0代表正常返回
}
free只是释放动态内存开辟出来的空间
free函数用来释放动态开辟的内存。
● 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
● 如果参数ptr是NULL指针,则函数什么事都不做。
2.2 calloc
C语言还提供了一个函数叫calloc,calloc函数也用来动态内存分配。原型如下:
void* calloc (size_t num, size_t size);
· 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
· 与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0。
(num是要开辟的个数,szie是字节数)
int main()
{
int* p = (int*)calloc(10,sizeof(int));
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;//返回1说明是异常返回
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
free(p);//free释放这块空间存放的东西,但是p指向的地址没有被释放
p = NULL;//让p为空指针
return 0;//返回0代表正常返回
}
2.3 realloc
● realloc函数的出现让动态内存管理更加灵活。
● 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时
候内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小
的调整。
函数原型如下:
void* realloc (void* ptr, size_t size);
● ptr是要调整的内存起始地址
● size 调整之后新大小
● 返回值为调整之后的内存起始位置。
● 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
● realloc在调整内存空间的是存在两种情况:
○ 情况1:原有空间之后有足够大的空间
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;//返回1说明是异常返回
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
//扩容
int* str = realloc(p, 80);
if (str != NULL)//不要用p来接收realloc返回的地址,如果内存扩容失败,p变为空指针,原先指向的40个字节空间就找不到了
{
p = str;
}
free(p);//free释放这块空间存放的东西,但是p指向的地址没有被释放
p = NULL;//让p为空指针
return 0;//返回0代表正常返回
}
realloc函数的工作原理:(假设把原先40字节大小的空间扩容到80个字节)
情况1:40个字节后面的空间不够继续增加40个字节,realloc会重新找一块80字节的空间,把原先40个字节空间的数据拷贝过来,原来的40个字节释放掉,返回新的地址,即这块80字节的地址。
情况2:原先40字节后面的空间够40个字节,直接在后面加上40个字节,返回的起始地址不变。
3.常见的动态内存错误
3.1对NULL指针的解引用操作
应该这样使用
3.2 对非动态开辟内存使用free释放
3.3 对动态开辟空间的越界访问
3.4 使用free释放动态开辟的内存的一部分
释放一部分是做不到的
p++,指向的不再是起始地址
3.5 对同一块动态内存空间多次free释放
3.6 忘记释放动态开辟的内存
free可能没有机会执行
p出了函数 销毁,str依然是空指针
应该这样写
传给printf的是首元素地址!!!
4.柔性数组
6.1柔性数组的特点
· 结构中的柔性数组成员前面必须至少一个其他成员。
· sizeof 返回的这种结构大小不包括柔性数组的内存。
· 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
struct S
{
int n;
int arr[];
};
int main()
{
struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
return 0;
}
标签:返回,字节,int,free,C语言,内存,动态内存,空间,柔性
From: https://blog.csdn.net/2402_83411382/article/details/143434532