内存空间如果简单划分的话,分为3个区:栈区,堆区,静态区
栈区主要是存放:局部变量,函数的形参,函数的返回值。
堆区主要是存放:malloc calloc realloc free动态开辟的内存空间。
静态区主要是存放:由static修饰的静态的变量,包括局部变量和全局变量。
int i = 0;//在栈上开辟一块大小为4byte的空间
float f = 0.0f;//在栈上开辟一块大小为4byte的空间
double d = 0.0;//在栈上开辟一块大小为8byte的空间
int arr[10] = { 0 };//在栈上连续开辟一块大小为40byte空间
上述开辟空间的大小都是固定的,开辟好之后就不能被修改。
这时候,就涉及到动态内存函数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
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(40);//动态开辟40个字节的空间,并将起始位置的地址赋值给整型指针ptr
//因为开辟可能成功,也有可能失败,故在使用ptr指针时,需要先判断指针是否为空
if (ptr == NULL)
{
printf("%s\n", strerror(errno));//打印错误信息
return 1;
}
//...
//动态内存空间的使用
//动态内存空间的释放
free(ptr);//释放只是释放了指针指向的空间,但是ptr还是指向原来的那块空间,为了确保安全,需要把ptr置为NULL
ptr = NULL;
return 0;
}
malloc和free#include
#include
#include
#include
int main()
{
int* ptr = malloc(sizeof(int), 10);//动态开辟10个整型的空间
//判断返回值
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//...
//相关操作
//内存释放
free(ptr);
ptr = NULL;
return 0;
}
realloc和free#include
#include
#include
#include
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
#include
int main()
{
int* p = malloc(10 * sizeof(int));
*p = 20;
free(p);
p = NULL:
return 0;
}
此代码中,使用malloc动态开辟10个整型的空间,可能开辟失败,返回空指针,如果一个指针没有明确的指向是不能直接进行解引用操作的!
#include
#include
#include
#include
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;
//p[i] <--> *(p + i)
}
//内存的释放
free(ptr);
ptr = NULL;
return 0;
}
#include
#inclue <stdlib.h>
int main()
{
int a = 0;
int* ptr = &a;
//...
free(ptr);
ptr = NULL;
return 0;
}
#include
#include
#include
#include
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++;
}
//ptr经过循环之后已经不再指向动态开辟内存的起始位置了。
free(ptr);
ptr = NULL;
return 0;
}
#include
#include
#include
#include
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
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//...相关操作
//...没有进行内存释放
return 0;
}
#include
#include
#include
#include
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//...相关操作
//内存释放
free(ptr);
//ptr = NULL;
*ptr = 10;
return 0;
}
有几点必须明确:
sizeof计算结构体的大小时,柔性数组成员不算在内。malloc函数进行内存分配,大小应大于结构体自身的大小。举例
#include
#include
#include
#include
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;
}