动态内存开辟
1.malloc、free
1.1 malloc的原型为:
void *malloc( size_t size );
1.2 malloc的用法:
看下面代码:
int* p=(int*)malloc(10*sizeof(int));
上面代码意思是开辟10个int类型大小的空间,将其强制转换为int型,并用int类型指针接收。
1.若开辟成功,则返回开辟空间的头指针。
2.若开辟失败,则返回空指针。
所以,用了malloc后一定要判断!
如下面代码:
#include<stdio.h>
#include<stdlib.h>// malloc 所在头文件
#include<errno.h>// errno,h 错误码库
int main() // 与 函数 strerror(错误信息报告) 搭配使用,将错误码转化为错误信息,并返回它的地址
{
// 我想向内存申请 10个 整形的 空间
int* p = (int*)malloc(/*INT_MAX*/10 * (sizeof(int)));// 因为 malloc 函数 返回的是 万能*(无类型)指针,所以需要转化类型
// malloc 函数 也有 开辟空间失败的时候,
// 比如 内存 只有 4 个 g ,我要开辟 8 g 空间,这肯定是会失败的,返回 空指针 NULL
if (p == NULL)
{
// 找出打印错误原因的方式
printf("%s\n", strerror(errno));// malloc(INT_MAX)
//输出 Not enough space
}
else
{
// 正常使用 空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;// 赋值 0 1 2 3 4 5 6 7 8 9
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));// 输出 0 1 2 3 4 5 6 7 8 9
}
printf("\n");
}
// 当动态申请的空间 不再使用的时候
// 就会把空间 还给 操作系统
// 这时候 就会用到 free 函数
return 0;
}
而malloc的使用需和free一起,即:用malloc开辟一处空间,必须由free来释放。否则会造成内存泄露!
1.3 free的原型:
void free( void *memblock );
1.4 free的用法:
free专门用于动态内存的释放和回收。如下代码:
#include<stdio.h>
#include<stdlib.h>// malloc,free 所在头文件
#include<errno.h>
int main()
{
// 我想向内存申请 10个 整形的 空间
int* p = (int*)malloc(10 * (sizeof(int)));
if (p == NULL)
{
// 找出打印错误原因的方式
printf("%s\n", strerror(errno));// malloc(INT_MAX)
//输出 Not enough space
}
else
{
// 正常使用 空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;// 0 1 2 3 4 5 6 7 8 9
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));// 0 1 2 3 4 5 6 7 8 9
}
printf("\n");
}
// 当动态申请的空间 不再使用的时候
// 就会把空间 还给 操作系统
// 这时候 就会用到 free 函数
free(p);// 用完了再释放,也就是说 在打印完之后(调用完之后),再释放(p的值没有改变,还可以通过它找到该空间)
// 虽然当前空间 不属于当前程序,但是依然 可以通过 p 找到 该空间,很有可能会破坏这个空间
// 所以先在这个 指针 依然很危险
p = NULL; // free函数 释放完空间后,不会改 p 的值,所以我们自己主动改
return 0;
}
// 最后请注意:free 是用来 释放 动态开辟的内存
// free 函数 的 特殊情况:
//1. 如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的
//2. 如果参数 ptr 是 NULL 指针,则函数 什么 都不做。
1.首先,将动态开辟的空间free掉。
2.再将free掉的空间的头指针制为空即可。
2.calloc
2.1 calloc原型:
void *calloc( size_t num, size_t size );
2.2 calloc用法:
calloc和malloc一样,都用于动态内存开辟,区别点在于calloc具有初始化功能,即:calloc可将开辟的空间进行初始化操作。
如下代码:
用法跟 malloc 函数差不多
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{ // 开一块空间,空间大小为 10 * int == 40 字节
int* p = (int*)calloc(10, sizeof(int));// 比 malloc 函数 多一个元素个数 参数
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for (i = 0; i < 10; i++)// 因为 p 为整形指针变量,指向一个 int 类型 元素,所以有 10个 int 元素
{
printf("%d ", *(p + i));// 0 0 0 0 0 0 0 0 0 0
} //calloc 在开辟好空间后,会把空间的所有字节内容全部初始化为 零
}
free(p);
p = NULL;// 狗头拿来!!
return 0;
}
3.realloc
3.1 realloc原型:
void *realloc( void *memblock, size_t size );
3.2 realloc用法:
有时我们会发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,为了合理的使用内存,我们一定会对内存的大小做灵活的调整,realloc函数就可以做到对动态开辟内存大小的调整。
如以下代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[], char* envp[])
{
int input;
int n;
int *numbers1;
int *numbers2;
numbers1=NULL;
if((numbers2=(int *)malloc(5*sizeof(int)))==NULL)//为numbers2在堆中分配内存空间
{
printf("malloc memory unsuccessful");
exit(1);
}
printf("numbers2 addr: %8X\n",(int)numbers2);
for(n=0;n<5;n++) //初始化
{
*(numbers2+n)=n;
//printf("numbers2's data: %d\n",*(numbers2+n));
}
printf("Enter new size: ");
scanf("%d",&input);
//重新分配内存空间,如果分配成功的话,就释放numbers2指针,
//但是并没有将numbers2指针赋为NULL,也就是说释放掉的是系统分配的堆空间,
//和该指针没有直接的关系,现在仍然可以用numbers2来访问这部分堆空间,但是
//现在的堆空间已经不属于该进程的了。
numbers1=(int *)realloc(numbers2,(input+5)*sizeof(int));
if(numbers1==NULL)
{
printf("Error (re)allocating memory");
exit(1);
}
printf("numbers1 addr: %8X\n",(int)numbers1);
/*for(n=0;n<5;n++) //输出从numbers2拷贝来的数据
{
printf("the numbers1's data copy from numbers2: %d\n",*(numbers1+n));
}*/
for(n=0;n<input;n++)//新数据初始化
{
*(numbers1+5+n)=n+5;
//printf("numbers1' new data: %d\n",*(numbers1+5+n));
}
printf("\n");
free(numbers1);//释放numbers1,此处不需要释放numbers1,因为在realloc()时已经释放
numbers1=NULL;
//free(numbers2);//不能再次释放
return 0;
}
1.如果当前内存段后有足够的空间,realloc()返回原来的指针。
2.如果当前内存段后没有足够的空间,realloc()返回一个新的内存段的指针