动态内存管理:malloc,calloc,ralloc,free
malloc:void* malloc(size_t size);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int arr[10] = { 0 };
//动态内存开辟
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d", *(p + i));
}
free(p);
//表示40个操作字节还给操作系统,可以用在其他方面
return 0;
}
INT-MAX整形最大
没有free并不是说内存空间就不回收了,当程序退出时,系统会自动回收内存空间的。
malloc这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟号空间的指针。
若失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值是void*,所以malloc函数并不知道,开辟空间的类型,具体在使用的时候使用者自己来决定。
free函数用来释放动态开辟的内存。
如果参数ptr只想的空间不是动态开辟的,那free函数的行是未定义的。
若参数ptr是NULL指针,则函数什么事也不做。
malloc,free都生命在stdlib.h头文件中。
calloc:void* calloc(size_t num, size_t size);
函数功能是为num个大小为size的元素开辟出一块空间,并且把空间的每一个字节初始化为0,与函数malloc的区别在于calloc会返回地址之前把申请的空间的每个字节初始化为0.
//开辟出10个整形空间
#include <stdio.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//打印
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d", *(p + i));
}
//释放
free(p);
p = NULL;
return 0;
return 0;
}
结果:0000000000
说明calloc在开辟空间时会将内容初始化为0,然后将这块空间存储地址在返回
calloc = malloc + memset
relloc
relloc函数的出现让他动态内存管理更加灵活。
有时我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的内存,我们一定会对内存的代下做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整。
void* relloc(void* ptr, size_t size)
ptr要调整的内存地址
size调整之后新大小
返回值为调整之后的内存起始位置
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移到新的空间。
#include <stdio.h>
int main()
{
int* p = (int*)malloc(40);
if (NULL == p)
{
printf("%s\n", strerror(errno));
return 1;
}
//使用
//1 2 3 4 5 6 7 8 9 10
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i + 1;
}
//扩容
int* ptr = realloc(p, 80);
if (ptr != NULL)
{
p = ptr;
}
//使用
for (i = 0; i < 10; i++)
{
printf("%d", *(p + i));
}
free(p);
p = NULL;
return 0;
}
(149.35)改动态通讯录
两种方式:
1.将(1)拷贝到(2)
测试开发相对简单,可以考虑曲线就业
1.对NULL指针的解引用操作
void test()
{
int* p = (int*)malloc(INT_MAX / 4);
*p = 20;
//如果p的值是NULL,就会出现问题
free(p);
}
一定要对malloc这样的函数做检测
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
*p = 20;
free(p);
p = NULL;
return 0;
}
2.对动态空间的越界访问
#include <errno.h>
#include <stdio.h>
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//方式
int i = 0;
for (i = 0; i < 10; i++)
{
p[i] = i;
}
free(p);
p = NULL;
return 0;
}
3.对非动态开辟内存使用free释放
int main()
{
int a = 10;
int* p = &a;
//...
free(p);
p = NULL;
return 0;
}
4.使用free释放一块动态开辟内存的一部分
#include <stdio.h>
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i;
p++;
}
//释放
free(p);
p = NULL;
return 0;
}
5.对同一块动态内存多次释放
int* p = (int*)malloc(40);
free(p);
free(p);
p = NULL;
return 0;
free(p)free将p的内存空间回收了,但p依旧指向该位置,此时p就是野指针
第二种:
printf("hello world\n");
char* p = "hello world\n";
printf(p);
printf("%s", p);
return 0;
6.动态开辟内存忘记释放(内存泄露)
#include <stdio.h>
void test()
{
int* p = (int*)malloc(100);
int flag = 0;
scanf("%d", &flag);
if (flag == 5)
//一旦flag=5,那么开辟的100个空间会找不到,无法释放
return;
free(p);
p = NULL;
}
int main()
{
test();
return 0;
}
错误代码(内存泄漏)
#include <stdio.h>
void GetMemory(char* p)
// 此处必须使用二级指针char** p
{
p = (char*)malloc(100);
//此处用*p
}
void test(void)
{
char* str = NULL;
GetMemory(str);
//str存放的就是动态开辟出的100字节地址
strcpy(str, "hello world");
printf(str);
//应该加上
//free(str);
//str = NULL;
}
int main()
{
test();
return 0;
}
错误点:1.GetMemory应该使用二级指针
2.程序进行完空间忘记释放