内存空间如果简单划分的话,分为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!
mallocvoid* 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("%sn", 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("%sn", 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("%sn", 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("%sn", 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 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("%sn", 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("%sn", 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("%sn", strerror(errno)); return 1; } //...相关操作 //...没有进行内存释放 return 0; }
- 动态内存释放后继续使用
#include柔性数组#include #include #include int main() { int* ptr = (int*)malloc(10 * sizeof(int)); if (ptr == NULL) { printf("%sn", 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("%sn", 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; }



