栈、堆、静态区
动态内存函数
-
malloc和free
-
函数原型
void* malloc( size_t size );
-
使用
#include <stdlib.h> #include <string.h> #include <errno.h> #include <stdio.h> int main() { // 申请10个整型空间 // int* p = (int*)malloc(10 * sizeof(int)); int* p = (int*)malloc(INT_MAX); // 分配失败 if (p == NULL) { printf("%s\n", strerror(errno)); } else { // 正常使用 for (int i = 0; i < 10; i++) { *(p + i) = i; } for (int i = 0; i < 10; i++) { printf("%d\t", *(p + i)); } } // 释放空间 // free用来释放动态开辟的空间 free(p); p = NULL; return 0; }
-
-
calloc
-
函数原型
void* calloc( size_t num, size_t size );
-
使用
#include <stdlib.h> #include <string.h> #include <errno.h> #include <stdio.h> int main() { // 申请10个整型空间 int* p = (int*)calloc(10, sizeof(int)); // 分配失败 if (p == NULL) { printf("%s\n", strerror(errno)); } else { // 正常使用 for (int i = 0; i < 10; i++) { *(p + i) = i; } for (int i = 0; i < 10; i++) { printf("%d\t", *(p + i)); } } // 释放空间 // free用来释放动态开辟的空间 free(p); p = NULL; return 0; }
-
-
malloc和calloc的区别
- calloc在返回申请好的空间地址之前,会给申请的空间初始化为0
- 而malloc则不会进行初始化操作,相对来说,malloc的效率略高
-
realloc
-
函数原型
void* realloc( void* memblock, size_t size );
-
使用
int main() { int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); } else { for (int i = 0; i < 5; i++) { *(p + i) = i; } for (int i = 0; i < 5; i++) { printf("%d\t", *(p + i)); } } printf("\n"); // realloc使用的注意事项 p = (int*)realloc(p, 40); // 有很大风险 for (int i = 5; i < 10; i++) { *(p + i) = i; } for (int i = 0; i < 10; i++) { printf("%d\t", *(p + i)); } free(p); p = NULL; return 0; }
-
注意事项
-
如果p指向的空间后面有足够的内存可以追加,则直接追加,返回p
-
如果p指向的空间后面没有足够的内存可以追加,则新开辟一块满足要求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟内存空间的地址
-
要用一个新的变量来接收realloc函数的返回值
p = (int*)realloc(p, INT_MAX);
-
假如此时用原来的p来接收realloc的返回值,如果realloc分配内存失败,则会返回NULL,那么,原本p指向的空间还有数据,但是现在就变成了没有数据,所以要用一个新的变量来接收realloc的返回值
int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); } else { for (int i = 0; i < 5; i++) { *(p + i) = i; } for (int i = 0; i < 5; i++) { printf("%d\t", *(p + i)); } } printf("\n"); int* ptr = (int*)realloc(p, INT_MAX); if (ptr != NULL) { p = ptr; } for (int i = 5; i < 10; i++) { *(p + i) = i; } for (int i = 0; i < 10; i++) { printf("%d\t", *(p + i)); } free(p); p = NULL; return 0; // 疑问? // free(p); // 上述代码中,如果原空间后面有足够的内存去追加,则realloc返回的是原空间的地址,用完之后free(p),可以理解 // 但是如果原空间后面没有足够的内存可以分配,那么realloc返回的是新开辟空间的地址,这时候 p = ptr; free(p); // 我们改变了p的指向,最后释放的是新开辟空间的内存,那么原来的内存空间是由系统自动释放了吗?这里希望评论区的大神给一个回复
-
-
-
动态内存开辟的常见错误
-
没有对malloc的返回值进行判断
int main() { int* p = (int*)malloc(100000000000000000000000000000); // 要对malloc函数的返回值进行判断 for (int i = 0; i < 5; i++) { *(p + i) = i; } free(p); p = NULL; return 0; }
-
对动态开辟的空间越界访问
int main() { int* p = (int*)malloc(10 * sizeof(int)); for (int i = 0; i < 20; i++) { *(p + i) = i; } free(p); p = NULL; return 0; }
-
使用free释放非动态开辟的空间
int main() { int arr[10] = {0}; int* p = arr; free(p); p = NULL; return 0; }
-
使用free释放动态内存的一部分
int main() { int*p = (int*)malloc(10 * sizeof(int)); if (p == NULL) return 1; for (int i = 0; i < 5; i++) { *p++ = i; } free(p); p = NULL; return 0; } // 两个风险 // 释放的是当前p指向之后的空间,本身就不允许 // 再也找不到p最初的指向了
-
对同一块动态内存重复释放
int main() { int* p = (int*)malloc(100); // 使用 // 释放 free(p); // 释放 free(p); return 0; } // 解决方法 // 第一次释放空间后,将p = NULL
-
动态开辟的空间忘记释放