C语言中的动态分配内存
4个动态分配内存函数:malloc
,free
,calloc
和realloc
,这些内存管理函数声明在在 stdlib.h头⽂件中
为什么要有动态内存分配?
程序运行时不确定需要多少内存空间。在编译期无法确定程序运行期间需要分配多大的内存块。此时就需要在运行时动态申请和释放内存
int x = 0;//在栈空间给变量分配4个字节
char ch = 'a';//在栈空间给变量分配1个字节
int arr[10] = {0};//在栈空间分配10个字节
// 但局限性很大 已经把空间写“死”
malloc
malloc(size_t size)
- 功能:分配指定大小的内存块,返回指向内存块的指针。
- 参数:
size
- 指定要分配的内存字节数。 - 返回值:如果分配成功,返回一个指向已分配内存的指针;如果分配失败,返回
NULL
。 - 使用
malloc
分配的内存需要使用free
函数释放,否则会造成内存泄漏。 - malloc分配的内存不会被初始化,内容是未定义的。
- 调用malloc分配指定大小的内存–检查返回值是否为NULL–使用分配到的内存–调用free释放内存
int *ptr = (int *)malloc(sizeof(int) * 10);
if (ptr == NULL) {
perror("malloc");//打印错误信息
return 1;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int)); // 申请一个整型变量的内存
if (ptr == NULL) {
printf("内存分配失败。\\n");
return 1;
}
*ptr = 100; // 给分配的内存赋值
printf("分配的内存值为: %d\\n", *ptr);
free(ptr); // 释放内存
return 0;
}
free
是用于释放由动态内存分配函数(如malloc
、calloc
、realloc
)分配的内存。free
函数帮助管理内存使用,避免内存泄漏。
free
函数的原型定义如下:
void free(void *ptr);
- 释放正确:确保在不再需要内存时调用
free
函数,避免内存泄漏。 - 释放顺序:如果多个内存块由同一个
malloc
调用分配,释放时应遵循相同的顺序。 - 释放已释放内存:释放同一块内存多次会导致未定义行为。
- 释放未分配内存:尝试释放未分配的内存会导致程序崩溃
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p;
p = (int *)malloc(sizeof(int)); // 分配内存
if (p != NULL) {
*p = 100; // 使用内存
printf("Memory allocated at address: %p\\n", p);
free(p); // 释放内存
p = NULL; // 避免释放已释放内存
}
return 0;
}
calloc
calloc 函数也⽤来动态内存分配, calloc
会给申请的每个字节初始化为0
,而malloc
不会初始化内存
代码原型
void *calloc(size_t num_elements, size_t size_of_element);
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr1, *ptr2;
// 使用 malloc 分配内存
ptr1 = (int *)malloc(10 * sizeof(int));
if (ptr1 == NULL) {
fprintf(stderr, "Memory allocation failed!\\n");
return 1;
}
// 注意:这里需要手动初始化内存
// 使用 calloc 分配内存
ptr2 = (int *)calloc(10, sizeof(int));
if (ptr2 == NULL) {
fprintf(stderr, "Memory allocation failed!\\n");
return 1;
}
// 注意:这里内存已经被初始化为0
// 输出结果,ptr2 的内容应该是0
for (int i = 0; i < 10; i++) {
printf("%d ", ptr2[i]);
}
printf("\\n")
// 释放内存
free(ptr1);
free(ptr2);
return 0;
}
realloc
realloc函数用于重新分配内存块的大小。
void *realloc(void *ptr, size_t size);
这个函数接受两个参数:
ptr
:这是要调整大小的内存块的指针。这个内存块必须是之前通过malloc
,calloc
,realloc
等函数分配的。size
:这是新的内存块的大小。如果size
比当前内存块的大小大,那么realloc
会增加内存块的大小;如果size
比当前内存块的大小小,那么realloc
会减少内存块的大小。
函数返回一个新的指针,指向调整后大小的内存块。如果调整大小失败,函数会返回NULL
。
例如,假设我们有一个通过malloc
分配的整型数组:
int *arr;
arr = (int *)malloc(10 * sizeof(int));
如果我们要增加数组的大小,可以使用realloc
:
arr = (int *)realloc(arr, 20 * sizeof(int));
如果我们要减小数组的大小,可以使用realloc
:
arr = (int *)realloc(arr, 5 * sizeof(int));
需要注意的是,realloc
函数在调整内存块大小时可能会导致数据丢失。如果在调用realloc
之前,内存块正在被使用,那么在调整大小后,数据的访问位置可能会改变。因此,在调用realloc
之前,应该确保内存块没有被使用,或者在调用realloc
后正确处理数据的访问位置。
此外,如果realloc
失败,函数会返回NULL
。此时,应该检查返回的指针是否为NULL
,并相应地处理错误情况。
realloc在调整内存空间的两种情况:
1:原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤,并且把数据拷贝过去,这样函数返回的是⼀个新的内存地址。
2:要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化,返回的起始地址还是旧的起始地址。