我们已经掌握的内存开辟方式有:
int val = 10; //在栈空间上开辟四个字节
char arr[10] = {0}; //在栈空间上开辟10个字节的连续空间
但是上述的开辟空间的方式有两个特点:
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。这时候就只能试试动态存开辟了。
malloc是C语言提供了一个动态内存开辟的函数。
void* malloc (size_t size); |
---|
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
free是C语言提供的一个专门用来做动态内存的释放和回收的函数,函数原型如下:
void free (void* ptr); |
---|
free函数用来释放动态开辟的内存。
注意:malloc和free都声明在 stdlib.h 头文件中。
calloc也是C语言提供用来动态内存分配的函数。原型如下:
void* calloc (size_t num, size_t size); |
---|
函数的功能是:
与函数 malloc 的区别:
举个例子
#include
#include
int main()
{
int *p = (int*)calloc(10, sizeof(int));
if(NULL != p)
{
//使用p
}
//使用结束释放p
free(p);
p = NULL;
return 0;
}
所以如何我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。
realloc函数的出现让动态内存管理更加灵活。有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。函数原型如下:
void* realloc (void* ptr, size_t size); |
---|
其中,ptr 是要调整的内存地址;size 调整之后新大小;返回值为调整之后的内存起始位置。这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
realloc在调整内存空间的是存在两种情况:
由于上述的两种情况,realloc函数的使用就要注意一些。
void test()
{
int *p = (int *)malloc(INT_MAX);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
改正后
void test()
{
int *p = (int *)malloc(INT_MAX);
if(p == NULL)
{
exit(-1);
}
*p = 20;
free(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++)//改为 for(i = 0; i < 10; i++)
{
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
void test()
{
int a = 10;
int *p = &a;
free(p);
}
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
忘记释放不再使用的动态开辟的空间会造成内存泄漏。
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
//缺少free(p);
}
int main()
{
test();
while(1);
}
切记:
动态开辟的空间一定要释放,并且正确释放 。
实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁。所以生命周期变长。
柔性数组(flexible array)是定义在C99 中的,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
例如:
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
有些编译器会报错无法编译可以改成:
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a;
例如:
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
printf("%d\n", sizeof(type_a));//输出的是4
//代码1
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
//业务处理
p->i = 100;
for(i=0; i<100; i++)
{
p->a[i] = i;
}
free(p);
这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
上述的 type_a 结构也可以设计为:
//代码2
typedef struct st_type
{
int i;
int *p_a;
}type_a;
type_a *p = (type_a *)malloc(sizeof(type_a));
p->i = 100;
p->p_a = (int *)malloc(p->i*sizeof(int));
//业务处理
for(i=0; i<100; i++)
{
p->p_a[i] = i;
}
//释放空间
free(p->p_a);
p->p_a = NULL;
free(p);
p = NULL;
上述 代码1 和代码2 可以完成同样的功能,但是 代码1 的实现有两个好处:
第一个好处是:方便内存释放
第二个好处是:这样有利于访问速度