动态内存分配malloc,calloc,realloc和释放空间free
动态内存开辟函数
malloc()函数
函数原型:
void* malloc(size_t size);
头文件:
#include <stdlib.h>
malloc函数向内存申请一块连续可用的且大小为size字节的空间
如果开辟空间成功则返回指向这块空间的指针,否则返回一个空指针NULL
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int i, j;
int* p = (int*)malloc(10 * sizeof(int));//向内存动态开辟10个整形的空间
if (p == NULL)
{
printf("%s\n", strerror(errno));
//若动态开辟内存失败,则会将一个错误码传递给errno,打印错误码相对应的错误信息
}
else
{
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (j = 0; j < 10; j++)
{
printf("%d ", *(p + j));
}
}
free(p);//释放动态开辟的空间(也就是将这块空间还给操作系统)
p = NULL;//并将其置为NULL,为什么呢?因为虽然p指向的这块空间被释放了,但是p存放的还是这块空间的地址
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int i, j;
int* p = (int*)malloc(INT_MAX);//#define INT_MAX 2147483647
if (p == NULL)
{
printf("%s\n", strerror(errno));
//若动态开辟内存失败,则会将一个错误码传递给errno,打印错误码相对应的错误信息
}
else
{
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (j = 0; j < 10; j++)
{
printf("%d ", *(p + j));
}
}
free(p);
p = NULL;
return 0;
}
输出:
Not enough space
free()函数
函数原型:
void free(void* ptr);//ptr指向一块待释放的空间
头文件:
#include <stdlib.h>
free函数是用来释放动态开辟的内存的
注意:ptr只能指向一块动态开辟的空间或空指针NULL
如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的
如果参数ptr是NULL空指针,则函数什么事情都不做
calloc()函数
函数原型:
void* calloc(size_t num,size_t size);//num个大小为size字节的元素
头文件:
#include <stdlib.h>
calloc()开辟一块num*size字节的空间,并把空间的每个字节都初始化为0
与malloc()函数的区别只在于calloc()会在返回地址之前把申请的空间的每个字节都初始化为0
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));//calloc向内存申请了一块10*sizeof(int)即40字节的空间
//并将此空间的每个字节都初始化为0
int i;
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
输出:
0 0 0 0 0 0 0 0 0 0
realloc()函数
函数原型:
void* realloc(void* ptr,size_t size);
ptr是要调整的内存地址
size调整后的大小
返回值为调整之后的内存空间的地址
realloc()调整内存空间有两种情况:
1.若是ptr所指向的内存空间的后面还有足够大的空间,则直接在其后追加内存空间,原来空间的数据不发生变化
2.若是ptr所指向的内存空间的后面没有足够大的空间,则realloc()函数会重新找一个内存区域,开辟一块满足需要的空间,并把原来内存中的数据拷贝过来,释放旧的内存空间,最后返回新开辟的内存空间地址
若是堆区没有一块满足需要的空间,则返回NULL
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
int* p = (int*)malloc(5*sizeof(int));
int* ptr = (int*)realloc(p, 40);
//int* ptr=realloc(NULL,10)等价于malloc(10)
if (ptr != NULL)
{
p = ptr;
}
else
{
return 0;
}
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (j = 0; j < 10; j++)
{
printf("%d ", *(p + j));
}
free(p);
p = NULL;
return 0;
}
常见的动态内存错误
1.空指针NULL不能解引用,下面操作是错误的
int* p=(int*)malloc(INT_MAX);//p=NULL
*p=20;
2.对动态开辟空间的越界访问
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int i, j;
int* p = (int*)malloc(10*sizeof(int));//向内存动态开辟10个整形的空间
if (p == NULL)
{
printf("%s\n", strerror(errno));
//若动态开辟内存失败,则会将一个错误码传递给errno,打印错误码相对应的错误信息
}
else
{
for (i = 0; i <=10; i++)
{
*(p + i) = i;//当i=10时越界访问
}
for (j = 0; j <=10; j++)
{
printf("%d ", *(p + j));
}
}
free(p);
p = NULL;
return 0;
}
3.对非动态开辟的空间使用free释放
int a=26;
int* p=&a;
free(p);
p=NULL;
4.使用free释放一块动态开辟内存的一部分
int *p=(int*)malloc(10);
p++;//p不再指向动态开辟的内存空间的起始位置
free(p);
p=NULL;
5.对同一块动态开辟的内存空间多次释放
int *p=(int*)malloc(10);
free(p);
free(p);
若是以下这种就可以↓:
int *p=(int*)malloc(10);
free(p);
p=NULL;
free(p);
6.对动态开辟的内存空间忘记释放(忘记释放不再使用的内存空间会导致内存泄露)
int* p=(int*)malloc(26);
//动态开辟内存空间后,没有用free(p)释放