动态内存函数的介绍

使用malloc和free

void* malloc (size_t size);

函数说明:malloc函数向操作系统申请一块连续可用的内存,并返回指向这块内存的指针。
返回值:void*,因为malloc并不知道你的内存放入什么类型的数据。
参数:size表示内存的大小(字节)

注意:malloc函数的声明在stdlib.h 头文件中

void free (void* ptr);

说明:free函数是专门是用来做动态内存的释放和回收的。
返回值:void,无返回值。
参数:ptr表示这块动态内存的首地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr = NULL;
int size = 10;

ptr = (int *)malloc(size * sizeof(int)); // 分配4个字节的动态内存
if(NULL == ptr)//判断ptr指针是否为空
{
printf("内存分配失败");
return 0;
}
// 给动态内存上分配的数组初始化
for (int i = 0; i < size; i++)
{
*(ptr + i) = 0;
}
for (int i = 0; i < size; i++)
{
printf("%d ", *(ptr + i));
}
free(ptr); // 释放ptr所指向的动态内存
ptr = NULL; // ptr指向0,拒绝野指针
return 0;
}

使用calloc函数

void* calloc (size_t num,size_t size);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr = (int *)calloc(10,sizeof(int)); // 分配4个字节的动态内存
if(NULL == ptr)//判断ptr指针是否为空
{
printf("内存分配失败");
return 0;
}
free(ptr); // 释放ptr所指向的动态内存
ptr = NULL; // ptr指向0,拒绝野指针
return 0;
}

使用realloc函数

void* realloc (void* ptr, size_t size);

说明:为了合理的分配内存,我们一定会对内存的大小做灵活的调整。
返回值:为调整之后的内存起始位置,这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
参数:
ptr:表示是要调整的内存地址
size:表示调整之后新大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
int main()
{
// 分配4字节的内存
int* ptr=(int *)calloc(1, sizeof(int)); // 长度
if (NULL == ptr)
{
printf("分配内存失败");
return 1;
}
*ptr = 666; // 赋值666
// 现在想给这块内存再扩展4个字节
ptr = (int *)realloc(ptr, 2 * sizeof(int));
*(ptr + 1) = 888; // 给扩展的4字节内存放入888
// 遍历扩展后的内存中所有的值
for (int i = 0; i < 2; i++)
{
printf("%d ", ptr[i]);
}
free(ptr);
ptr = NULL;
return 0;
}

注意事项:realloc在调整扩展内存空间时,存在两种情况

情况1:原有空间有足够的空间,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

情况2:原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。

常见的动态内存错误

(1)每次动态分配都要做检查

1
2
3
4
if(ptr == NULL)
{
printf("内存分配失败");
}

(2)动态开辟空间的越界访问

1
2
3
4
5
6
int i = 0
int *ptr = (int *)malloc(10*sizeof(int));
for(i = 0;i<= 10;i++)//越界
{
*(ptr + i) = i;
}

(3)非动态开辟内存使用free释放

1
2
3
int a = 10;
int *ptr = &a;
free(ptr);//错误释放非动态开辟的内存

(4)使用free释放一块从非首地址开始的动态内存

1
2
3
int *ptr = (int *)malloc(10*sizeof(int));
ptr++;
free(ptr);//异常

(5)对同一块动态内存多次释放

1
2
free(ptr);
free(ptr);

(6)动态开辟内存忘记释放(内存泄漏)

1
2
3
4
5
6
7
8
9
10
void test()
{
int *ptr = (int *)malloc(10*sizeof(int));
if(ptr == NULL)
{
printf("内存分配失败");
}
//进行free释放
return;
}

几个经典的笔试题

题一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void GetMemory(char *p)
{
p = (char *)malloc(100);//p->malloc(100)
//且指针未被释放
return;
}
int main()
{
char *str = NULL;//str->null
GetMemory(str);//p->null
strcpy(str,"hello world");//strcpy是属于非法写内存NULL,程序异常
printf(str);

return 0;
}

报错:编译正常,运行报错

题二

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
char *GetMemory()
{
char p[] = "hello world";
return p;//局部变量,调用程序后进行回收
}
int main()
{
char *str = NULL;
str = GetMemory();//str->非法内存
printf(str);
return 0;
}

报错:编译错误

题三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void GetMemory(char **p,int num)
{
p = (char *)malloc(num);
return;
}
int main()
{
char *str = NULL;
GetMemory(&str,100);
strcpy(str,"ethaniel");
printf(str);
return 0;
}

报错:未报错,但是没释放动态内存

题四

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<string.h>
int main()
{
char *str = (char *)malloc(100);
strcpy(str,"ethaniel");
free(str);
if(str !=NULL)//str已释放,再次调用生成野指针
{
strcpy(str,"blog");
printf(str);
}
return 0;
}

报错:释放后再次调用导致的报错