动态内存管理
内存空间如果简单划分的话,分为3个区:栈区,堆区,静态区
栈区主要是存放:局部变量,函数的形参,函数的返回值。
堆区主要是存放:malloc calloc realloc free 动态开辟的内存空间。
静态区主要是存放:由static 修饰的静态的变量,包括局部变量和全局变量。
内存开辟的方式
- 在栈区开辟空间:
int i = 0;
float f = 0.0f;
double d = 0.0;
int arr[10] = { 0 };
上述开辟空间的大小都是固定的,开辟好之后就不能被修改。
- 在堆区开辟空间:
这时候,就涉及到动态内存函数malloc calloc realloc free !
void* malloc(size_t size);
malloc 函数是用来向内存申请一块空间的,要是申请成功,则返回该空间的起始地址;申请失败,返回空指针NULL .
几点注意事项:
- 要是申请成功,该块空间并未初始化。
- 如果
size 是0,标准未定义该行为,结果取决于不同的编译器。 void* 类型的指针不能直接进行解引用操作,得先将其转化为具体类型的指针。
void free(void* ptr);
free 函数是用来释放动态内存函数开辟的内存空间的,因为只开辟,不释放,会使得内存泄漏。
几点注意事项:
ptr 指针只能是指向的空间是malloc calloc realloc 函数开辟的。- 如果
ptr 是NULL ,则free 函数什么也不干。 - 不能对一块由动态内存函数开辟的空间多次用
free 释放。
void* calloc(size_t num, size_t size);
跟malloc 函数类似,calloc 函数也是用来开辟内存空间的,不过于malloc 不同的是,calloc 函数是用来开辟num 个大小为size 的连续空间的。
需要注意的是:
calloc 同样是返回泛型指针void* ,不能直接对其进行解引用操作。calloc 函数开辟空间成功,返回的是空间的起始地址;开辟失败返回的是空指针NULL 。calloc 在开辟空间的时候,顺便将空间的每个字节全部初始化为0。
void* realloc(void* ptr, size_t size);
realloc 是用来调整由动态内存函数开辟空间的大小的函数。
需要注意的点是:
ptr 指向的是由动态内存函数开辟空间的起始地址;调整之后,新内存空间的大小是size 。- 如果调整空间成功,返回调整空间的地址;要是失败,返回空指针
NULL 。 - 如果给定的
size 大小是0,则该函数跟malloc 一样,啥事也不干。 realloc 返回的地址可能是原来的地址,也有可能是经过调整之后新的地址。
realloc 的两种开辟方式:
动态内存函数的使用
calloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(40);
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(ptr);
ptr = NULL;
return 0;
}
malloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = malloc(sizeof(int), 10);
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(ptr);
ptr = NULL;
return 0;
}
realloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(40);
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
int* p = (int*)free(ptr, 80);
if (p != NULL)
{
ptr = p;
}
free(ptr);
ptr = NULL;
return 0;
}
动态内存开辟中有关的错误
- 对
NULL 进行解引用。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = malloc(10 * sizeof(int));
*p = 20;
free(p);
p = NULL:
return 0;
}
此代码中,使用malloc 动态开辟10 个整型的空间,可能开辟失败,返回空指针,如果一个指针没有明确的指向是不能直接进行解引用操作的!
- 操作越过动态开辟的空间。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
for (int i = 0; i <= 10; i++)
{
ptr[i] = i;
}
free(ptr);
ptr = NULL;
return 0;
}
- 释放非动态开辟的内存
#include <stdio.h>
#inclue <stdlib.h>
int main()
{
int a = 0;
int* ptr = &a;
free(ptr);
ptr = NULL;
return 0;
}
- 释放动态开辟内存的一部分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
for (int i = 0; i < 5; i++)
{
ptr++;
}
free(ptr);
ptr = NULL;
return 0;
}
- 对同一块动态开辟的内存多次释放
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(ptr);
ptr = NULL;
free(ptr);
ptr = NULL;
return 0;
}
- 忘记释放动态开辟的内存(导致内存泄漏)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
return 0;
}
- 动态内存释放后继续使用
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(ptr);
*ptr = 10;
return 0;
}
柔性数组
有几点必须明确:
- 柔性数组只可能出现在结构体中。
- 柔性数组成员必须是结构体中的最后一个成员,也就是说,结构体中至少有两种成员。
- 使用
sizeof 计算结构体的大小时,柔性数组成员不算在内。 - 含有柔性数组成员的数组应使用
malloc 函数进行内存分配,大小应大于结构体自身的大小。
举例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct S
{
char c;
int i;
int arr[0];
}type_s;
int main()
{
type_s* p = (type_s*)malloc(sizeof(type_s) + 100 * sizeof(int));
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
p->c = 'w';
p->i = 0;
for (int i = 0; i < 100; i++)
{
p->arr[i] = i;
}
free(p);
p = NULL;
return 0;
}
|