在空间使用未知的情况下,如果使用数组,就必须事先指定申请的空间大小,当数据太大数组空间不足以存储,当数据太小又会造成空间的浪费。所以,我们要学会动态内存开辟。
动态内存函数
malloc
void* malloc(size_t size);
//size表示要申请的空间的大小,单位字节
函数向内存申请一块连续的内存空间:
如果申请成功,返回指向该空间的指针
如果申请失败,返回NULL指针
函数返回类型是void*,所以使用时要进行类型转换
calloc
void* calloc(size_t num, size_t size);
//num表示要申请的元素的个数
//size表示每个元素的大小,单位字节
函数向内存申请能够存储num个大小为size的元素的连续空间,并把空间的每个字节都初始化为0。与malloc功能的唯一区别就是初始化空间。
如果申请成功,返回指向该空间的指针
如果申请失败,返回NULL指针
函数返回类型是void*,所以使用时要进行类型转换
realloc
void* realloc(void* ptr, size_t size);
//ptr表示一个曾用malloc,calloc,realloc申请过的内存的指针,如果是NULL,则新开辟一块空间
//size表示size表示调整后的空间的总大小,单位字节
函数可以通过空间指针对已经申请过的空间进行调整
如果申请失败,返回NULL空指针
如果申请成功,返回的指针分为两种情况:
原有空间之后的空间大于调整后空间的大小,那么返回的指针就是调整之前的空间的指针
原有空间之后的空间不够大,小于调整后空间的大小,函数会在向内存再申请一块空间,将之前空间的数据拷贝,并释放之前申请的空间,返回新申请的内存空间地址。
如果传入的指针是NULL,则会开辟一块新空间,作用与malloc无异
free
void free(void*ptr);
//ptr表示要释放的空间地址
函数对通过动态开辟的内存进行释放
free不可对不是动态开辟的内存进行释放
如果传入的指针是NULL,则函数不进行任何操作
free不可对动态开辟的内存而此释放
free后的空间指针不会置NULL
常见的动态内存错误
对NULL指针的解引用操作
int main()
{
int* p = (int*)malloc(INT_MAX/4);
*p = 20;
free(p);
p = NULL;
return 0;
}
INT_MAX是一个非常大的数,动态开辟时可能不成功,p就是空指针,对它解引用会出错。
所以动态开辟后要对指针进行检查。
对动态开辟空间的越界访问
void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}
对非动态开辟内存使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}
使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
动态开辟内存忘记释放(内存泄漏)
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}