1. malloc()
2. calloc()
3. realloc()
4. free()
malloc()函数用于在堆(heap)上分配指定字节数的内存块。分配的内存不会被初始化,其内容是未定义的。
函数原型
void *malloc(size_t size);
参数:
size:要分配的内存字节数。
返回值:
成功:返回一个指向分配内存的指针。
失败:返回 `NULL` 指针。
示例
#include
#include
int main() {
int *ptr;
int n;
printf("请输入要分配的整数个数: ");
scanf("%d", &n);
ptr = (int *)malloc(n * sizeof(int));
if (ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 使用分配的内存
for(int i = 0; i < n; i++) {
ptr[i] = i + 1;
printf("ptr[%d] = %d\n", i, ptr[i]);
}
// 释放内存
free(ptr);
return 0;
}
输出:
calloc()函数用于在堆上分配内存,并初始化分配的内存块为零。与 malloc() 不同,calloc()接受两个参数,分别表示元素的数量和每个元素的大小。
void *calloc(size_t num, size_t size);
参数:
num:元素的数量。
size:每个元素的大小。
返回值:
成功:返回一个指向分配内存的指针。
失败:返回一个 NULL指针。
示例
#include
#include
int main() {
int *ptr;
int n;
printf("请输入要分配的整数个数: ");
scanf("%d", &n);
ptr = (int *)calloc(n, sizeof(int));
if (ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 使用分配的内存
for(int i = 0; i < n; i++) {
printf("ptr[%d] = %d\n", i, ptr[i]); // 初始值为0
}
// 释放内存
free(ptr);
return 0;
}
输出:
realloc()函数用于调整之前分配的内存块的大小。如果之前分配的内存块不足以满足需求,realloc()会尝试在堆上分配更大的内存块,并将旧内存块的内容复制到新内存块中。
void *realloc(void *ptr, size_t size);
参数:
ptr:指向之前分配的内存块的指针。
size:新的内存块大小。
返回值:
成功:返回一个指向新内存块的指针。
失败:返回 `NULL` 指针(原有内存块保持不变)。
示例
#include
#include
int main() {
int *ptr;
int n, new_n;
printf("请输入要分配的整数个数: ");
scanf("%d", &n);
ptr = (int *)malloc(n * sizeof(int));
if (ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 初始化
for(int i = 0; i < n; i++) {
ptr[i] = i + 1;
}
printf("当前数组大小: %d\n", n);
printf("请输入新的数组大小: ");
scanf("%d", &new_n);
ptr = (int *)realloc(ptr, new_n * sizeof(int));
if (ptr == NULL) {
printf("内存重新分配失败\n");
return 1;
}
// 初始化新分配的部分
for(int i = n; i < new_n; i++) {
ptr[i] = i + 1;
}
printf("新数组大小: %d\n", new_n);
for(int i = 0; i < new_n; i++) {
printf("ptr[%d] = %d\n", i, ptr[i]);
}
// 释放内存
free(ptr);
return 0;
}
输出:
free() 函数用于释放之前通过 malloc(), calloc() 或 realloc() 分配的内存。释放内存后,程序不能再访问该内存区域,否则会导致未定义行为。
void free(void *ptr);
参数:
ptr:指向要释放的内存块的指针。
返回值:
无
避免内存泄漏: 每次使用 malloc(), calloc()或 realloc()分配内存后,必须使用 free()释放内存,否则会导致内存泄漏。
避免悬挂指针:释放内存后,应将指针设置为 NULL,以避免悬挂指针(指向已释放内存的指针)带来的问题。
示例
#include
#include
int main() {
int *ptr = (int *)malloc(5 * sizeof(int));
if (ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 使用内存
for(int i = 0; i < 5; i++) {
ptr[i] = i + 1;
}
// 释放内存
free(ptr);
ptr = NULL; // 避免悬挂指针
return 0;
}
输出:
1. 可变大小的数据结构:如链表、动态数组、树、图等。
2. 处理大型数据集: 当数据量在运行时确定时,动态分配内存可以节省内存空间。
3. 文件处理: 读取文件内容到内存中时,可能需要动态分配内存。
4. 网络编程:处理网络数据包时,可能需要动态分配内存。
1. 内存泄漏:分配的内存没有被释放,导致内存逐渐耗尽。
2. 悬挂指针:释放内存后未将指针设置为 NULL,导致后续访问无效内存。
3.多次释放:对同一指针多次调用 free(),导致未定义行为。
4. 分配失败未处理: 未检查 malloc(), calloc() 或 realloc() 的返回值是否为 NULL。
1. 总是检查分配结果: 每次调用 malloc(), calloc() 或 realloc() 后,检查返回值是否为 NULL。
2. 释放所有分配的内存:确保每个 malloc(), calloc() 或 realloc() 对应一个 free()。
3. 避免悬挂指针:释放内存后,将指针设置为 NULL。
4. 使用工具检测内存错误: 使用诸如 Valgrind 等工具检测内存泄漏和悬挂指针。
C语言还提供了其他内存管理函数,如 alloca(),用于在栈上分配内存。
alloca()函数用于在栈上分配内存,分配的内存会在函数返回时自动释放,不需要调用 free()。
void *alloca(size_t size);
参数:
size:要分配的内存字节数。
返回值:
成功:返回一个指向分配内存的指针。
失败:返回 NULL指针。
注意
栈空间限制:栈空间有限,过大的分配可能导致栈溢出。
不可移植性:alloca()不是标准C的一部分,行为可能因平台而异。
#include
#include
int main() {
int *array = NULL;
int n, i;
printf("请输入数组的大小: ");
scanf("%d", &n);
array = (int *)malloc(n * sizeof(int));
if (array == NULL) {
printf("内存分配失败\n");
return 1;
}
// 输入数组元素
for(i = 0; i < n; i++) {
printf("请输入元素 %d: ", i);
scanf("%d", &array[i]);
}
// 输出数组元素
printf("数组元素为: ");
for(i = 0; i < n; i++) {
printf("%d ", array[i]);
}
printf("\n");
// 释放内存
free(array);
array = NULL;
return 0;
}
输出:
动态内存分配是C语言中一个强大的特性,能够在运行时灵活地分配和管理内存。