目录
malloc
void* malloc (size_t size);
malloc动态的内存分配,只负责在堆区上申请空间,并且返回起始地址,不初始化内存空间
如果开辟成功返回开辟好空间的指针,如果开辟失败返回一个NULL的指针。
free
void free (void* ptr);
free是用来释放动态开辟的内存空间
int main()
{
//int arr[10] = {0};
//申请空间
int* p = (int*)malloc(40); //40表示的是字节数
if (p == NULL)
{
return -1;
}
//开辟成功了
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
//释放空间
free(p);
p = NULL;
return 0;
}
calloc
void* calloc (size_t num, size_t size);
calloc函数在堆区上申请空间,并且初始化为0,返回起始地址。
int main()
{
//申请10个int的空间
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++)
{
*(p + i) = i;
}
}
realloc
void* realloc (void* ptr, size_t size);
realloc用来调整空间,空间不够,可以进行调整,返回值为调整之后的起始地址,
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
int main()
{
//申请10个int的空间
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++)
{
*(p + i) = i;
}
//realloc调整空间
//空间不够了,增加空间至20 个int
int*ptr = (int*)realloc(p, 20*sizeof(int)); //第二个参数要的是字节
if (ptr != NULL)
{
p = ptr;
}
else
{
return -1;
}
for (i = 10; i < 20; i++)
{
*(p + i) = i;
}
//打印
for (i = 0; i < 20; i++)
{
printf("%d ", *(p + i));
}
//释放空间
free(p);
p = NULL;
return 0;
}
常见的动态内存错误
1.对空指针*
int main()
{
int*p = (int*)malloc(20);
if (p == NULL)
return -1;
//
*p = 0;//直接这样写代码是有风险的!!!
return 0;
}
2.对动态开辟的内存越界访问
int main()
{
int* p = (int*)malloc(200);
if (p == NULL)
{
return -1;
}
//使用
int i = 0;
//越界访问
for (i = 0; i < 80; i++)
{
*(p + i) = i;
}
for (i = 0; i < 80; i++)
{
printf("%d\n", *(p + 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释放一块动态开辟内存的部分
int main()
{
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
return -1;
}
//使用
int i = 0;
for (i = 0; i < 5; i++)
{
*p++ = i; //p已经不在指向起始位置
}
//释放
free(p);
p = NULL;
return 0;
}
5.对同一块动态内存多次释放
int main()
{
int *p = (int*)malloc(40);
if (p == NULL)
return -1;
//使用
//...
//2次释放-是错误的
free(p);
free(p);
return 0;
}
经典笔试题
1.
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;
}
运行上面代码会导致程序奔溃,内存泄漏:
1.str传给p的时候,是值传递,p是str的临时拷贝,当malloc开辟的空间的起始地址方在p中的时候,不会影响str,str依然是NULL 。
2.当str为NULL,strcpy想把hello world拷贝到str指向的空间时,程序就奔溃,因为null没法访问。
改进:
方法一:
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;
}
方法二:
char* GetMemory(char* p)
{
p = (char*)malloc(100);
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory(str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
2.
返回栈空间地址的问题
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
//程序运行,打印随机值
return 0;
}
发现运行上面的程序是打印随机值。因为每一次运行都会重新开辟一块空间。
3.
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello"); //内存泄漏没有free
printf(str);
}
int main()
{
Test();
return 0;
}
运行上面代码会发现内存泄漏,因为没有进行内存释放。
4.
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;
}
提前释放了内存。
柔性数组
柔性数组:结构体中最后一个元素允许是未知大小的数组
1.结构中的柔性数组成员前面必须至少一个其他成员。
2.sizeof 返回的这种结构大小不包括柔性数组的内存。
3.包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于
结构的大小,以适应 柔性数组的预期大小。
方法1:
struct st_type2
{
int i;
int a[0];//柔性数组成员
};
#include<string.h>
#include <errno.h>
struct st_type
{
int i;//4
int a[];//柔性数组成员
};
int main()
{
//printf("%d\n", sizeof(struct st_type));
//包含柔性数组成员的结构体的使用,要配合malloc这样的动态内存分配函数使用
//struct st_type st;
struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type) + 10*sizeof(int));
if (ps == NULL)
{
printf("%s\n", strerror(errno));
return -1;
}
//开辟成功了
ps->i = 100;
int i = 0;
for (i = 0; i < 10; i++)
{
ps->a[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", ps->a[i]);
}
//a数组的空间不够了,希望调整为20个整型数据
struct st_type* ptr = (struct st_type*)realloc(ps, sizeof(struct st_type)+20*sizeof(int));
if (ptr == NULL)
{
printf("扩展空间失败\n");
return - 1;
}
else
{
ps = ptr;
}
//使用
//...
//释放
free(ps);
ps = NULL;
return 0;
}
struct st_type
{
int i;//4
int* a;//4
};
int main()
{
struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type));
ps->i = 100;
ps->a = (int*)malloc(10*sizeof(int));
int i = 0;
for (i = 0; i < 10; i++)
{
ps->a[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", ps->a[i]);
}
//a指向的空间不够了,希望可以调整大小
int* ptr = (int*)realloc(ps->a, 20*sizeof(int));
if (ptr == NULL)
{
printf("扩容失败\n");
return -1;
}
else
{
ps->a = ptr;
}
//使用
//..
//释放
free(ps->a);
ps->a = NULL;
free(ps);
ps = NULL;
return 0;
}