malloc/realloc/calloc/free

malloc

malloc函数: 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。
原型:extern void *malloc(unsigned int num_bytes);
功能:分配长度为num_bytes字节的内存块
返回值:如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。void* 表示未确定类型的指针,void *可以指向任何类型的数据,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者...)
例如:
int* p;
p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中
double *pd=(double *) malloc (sizeof(double)*12);//分配12个double型存储单元,并将首地址存储到指针变量pd中
第一、malloc 函数返回的是 void * 类型。对于C++,如果你写成:p = malloc (sizeof(int)); 则程序无法通过编译,报错:“不能将 void* 赋值给 int * 类型变量”。所以必须通过 (int *) 来将强制转换。而对于C,没有这个要求,但为了使C程序更方便的移植到C++中来,建议养成强制转换的习惯。
第二、函数的实参为 sizeof(int) ,用于指明一个整型数据需要的大小。如果你写成:
int* p = (int *) malloc (1);
代码也能通过编译,但事实上只分配了1个字节大小的内存空间,当你往里头存入一个整数,就会有3个字节无家可归,而直接“住进邻居家”!造成的结果是后面的内存中原有数据内容被改写。

typedef struct data_type {
      int age;
      char name[20];
} data;
    
data *bob;
bob = (data*) malloc( sizeof(data) );
if( bob != NULL ) {
      bob->age = 22;
      strcpy( bob->name, "Robert" );
      printf( "%s is %d years old\n", bob->name, bob->age );
}
free( bob );

realloc

原型:extern void *realloc(void *mem_address, unsigned int newsize);
语法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。//新的大小一定要大于原来的大小不然的话会导致数据丢失!
头文件:#include <stdlib.h> 有些编译器需要#include <malloc.h>,在TC2.0中可以使用alloc.h头文件
功能:先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域,同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。 
注意:这里原始内存中的数据还是保持不变的。当内存不再使用时,应使用free()函数将内存块释放。
举例1:
  从这个例子可以看出realloc函数的功能。
  
#include<stdio.h>
#include<stdlib.h>
int main()
{
  int i;
  int *pn=(int *)malloc(5*sizeof(int));
  printf("%p\n",pn);
  for(i=0;i<5;i++)
  scanf("%d",&pn[i]);
  pn=(int *)realloc(pn,10*sizeof(int));
  printf("%p\n",pn);
  for(i=0;i<5;i++)
  printf("%3d",pn[i]);
  printf("\n");
  free(pn);
  return 0;
}
realloc使用总结
1. realloc失败的时候,返回NULL
2. realloc失败的时候,原来的内存不改变,不会释放也不会移动
3. 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址
4. 如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。
5. 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的
6.传递给realloc的指针可以为空,等同于malloc。

calloc

calloc是一个C语言函数
函数名: calloc
原型:void *calloc( size_t count, size_t size );
功 能: 在内存的动态存储区中分配count个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
跟malloc的区别:calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。
头文件:stdlib.h或malloc.h

free

语法: 
  #include <stdlib.h>
  void free( void *ptr );
 功能: 函数释放指针ptr指向的空间,以供以后使用。指针ptr 必须由先前对malloc(), calloc(), realloc()的调用返回。例如: 
例:
    typedef struct data_type {
      int age;
      char name[20];
    } data;
    
    data *willy;
    willy = (data*) malloc( sizeof(willy) );
    ...
    free( willy );



参考:
http://baike.baidu.com/view/736228.htm
http://baike.baidu.com/view/736230.htm
http://baike.baidu.com/view/653964.htm
http://baike.baidu.com/view/512783.htm
<think>嗯,用户现在想了解mallocfree函数的含义以及它们在内存管理中的作用。首先,我需要回忆一下自己对这两个函数的理解。malloc是C语言中用于动态分配内存的函数,而free则用于释放之前分配的内存。动态内存分配是在程序运行时根据需要分配内存,这在处理不确定大小的数据结构时非常有用,比如数组或者链表。 用户的问题包括含义、使用场景和内存管理中的作用。我需要确保覆盖这三个方面。首先,解释mallocfree的基本定义,然后讨论它们的使用场景,比如动态数据结构、文件I/O时的缓冲区,或者跨函数传递数据。接着,要说明它们在内存管理中的角色,比如避免内存泄漏和碎片化。 需要注意的是,用户可能对动态内存分配不太熟悉,所以需要用简单的例子来说明。例如,用malloc分配一个整数数组,然后用free释放。同时,要提到使用这些函数时的常见错误,比如忘记释放内存导致泄漏,或者重复释放同一块内存。 用户提供的引用中提到malloc/free直接操作字节级别的内存,需要手动计算大小,返回void指针。这提醒我要强调类型转换的重要性,比如将void指针转换为特定类型的指针。另外,引用中还提到内存池的概念,这可能和malloc的实现有关,比如缓冲池的使用减少系统调用,提高性能。不过用户的问题更关注基本含义和作用,可以稍微提及原理,但不需要深入。 另外,用户可能想知道为什么需要动态内存分配,而不仅仅是静态或自动分配。这时候需要解释静态分配的局限性,比如固定大小,无法在运行时改变。动态分配提供了灵活性,但需要手动管理,这也是内存泄漏等问题出现的原因。 在解释过程中,要确保语言简洁,避免技术术语过多,但又要准确。可能需要举一些实际的例子,比如动态创建链表节点,或者处理用户输入不确定大小的数据。同时,要强调正确使用mallocfree的重要性,避免常见错误。 最后,用户可能还想了解替代方案,比如C++中的new/delete,或者其他语言中的自动内存管理。不过根据问题,用户关注的是C语言中的malloc/free,所以可以集中在C的范围内。 总结一下,回答的结构应该是: 1. 定义和基本用法 2. 使用场景 3. 内存管理中的作用 4. 常见错误和注意事项 5. 示例代码 6. 相关问题扩展 需要检查是否有遗漏的点,比如内存分配的底层机制,但用户的问题可能不需要深入到这里,除非必要。确保引用中的信息被正确使用,比如提到缓冲池和系统调用优化的部分,可以放在内存管理作用的部分,说明malloc的高效性原因。 现在需要把这些点组织成连贯的中文段落,使用用户要求的格式,分章节,使用LaTeX公式(如果有的话),代码示例等。同时,生成相关问题,如内存泄漏检测工具或与new的区别,这些可以帮助用户进一步学习。</think>#### 一、`malloc`与`free`函数的基本定义 1. **`malloc`(Memory Allocation)** - **含义**:C标准库函数,用于在**堆(Heap)内存**中动态分配指定字节数的连续内存空间。 - **语法**:`void* malloc(size_t size);` - `size`:请求分配的内存字节数。 - 返回值:成功时返回指向分配内存的`void*`指针,失败时返回`NULL`[^1][^3]。 - 示例: ```c int* arr = (int*)malloc(10 * sizeof(int)); // 分配10个整数的内存空间 ``` 2. **`free`** - **含义**:释放通过`malloc`、`calloc`或`realloc`分配的堆内存,将其返还给系统。 - **语法**:`void free(void* ptr);` - `ptr`:指向待释放内存的指针(必须是由动态分配函数返回的指针)[^1][^3]。 - 示例: ```c free(arr); // 释放之前分配的数组内存 arr = NULL; // 避免悬空指针 ``` --- #### 二、核心作用与内存管理 1. **动态内存管理的意义** - **突破静态分配限制**: - 静态分配(如全局变量、栈变量)需在编译时确定大小,而`malloc`允许运行时按需分配内存[^1][^4]。 - **灵活性与资源控制**: - 处理未知大小的数据(如用户输入、文件内容)。 - 避免栈溢出(大内存需从堆分配)。 2. **内存管理中的角色** - **堆内存分配器**: - `malloc`通过内存池(Memory Pool)管理堆内存,减少频繁调用系统函数(如`sbrk`)的开销[^4]。 - 示例:预分配大块内存作为缓冲池,再分割成小块供程序使用[^4]。 - **碎片化控制**: - 合并相邻空闲块(通过`free`实现),减少内存碎片[^4]。 --- #### 三、典型使用场景 1. **动态数据结构** - **链表/树节点**: ```c struct Node { int data; struct Node* next; }; struct Node* node = (struct Node*)malloc(sizeof(struct Node)); ``` 2. **文件/网络I/O缓冲区** - **读取未知大小的文件**: ```c FILE* file = fopen("data.bin", "rb"); fseek(file, 0, SEEK_END); long size = ftell(file); char* buffer = (char*)malloc(size); // 动态分配与文件大小匹配的内存 ``` 3. **跨函数内存传递** - **返回动态创建的数组**: ```c int* create_array(int size) { return (int*)malloc(size * sizeof(int)); } ``` --- #### 四、关键注意事项 1. **内存泄漏(Memory Leak)** - **原因**:分配后未调用`free`释放。 - **后果**:程序持续占用内存,最终导致系统资源耗尽。 2. **悬挂指针(Dangling Pointer)** - **场景**:释放内存后未置空指针: ```c int* ptr = malloc(sizeof(int)); free(ptr); *ptr = 10; // 危险!访问已释放的内存 ``` 3. **双重释放(Double Free)** - **错误示例**: ```c free(ptr); free(ptr); // 未定义行为,可能破坏内存管理结构 ``` --- #### 五、底层实现原理(简析) 1. **内存池化思想** - `malloc`通过`sbrk`或`mmap`向操作系统申请大块内存,将其划分为不同大小的块(Chunk)管理[^4]。 - 分配策略: - 首次适应(First Fit) - 最佳适应(Best Fit) 2. **内存块结构** - 每个内存块包含元数据(如块大小、是否空闲)和用户数据区[^4]。 - 示意图: $$ \text{Header} \rightarrow | \text{Size} | \text{Flags} | \quad \text{User Data} \quad | $$ --- #### 六、与其他内存分配方式的对比 | **方式** | **分配区域** | **生命周期** | **灵活性** | |----------------|------------|------------------|------------------| | **静态分配** | 数据段 | 程序整个运行周期 | 固定大小,不可变 | | **自动分配** | 栈 | 函数执行期间 | 自动释放,速度快 | | **动态分配** | 堆 | 手动控制 | 按需分配,灵活 | --- #### 七、最佳实践 1. **分配后检查指针**: ```c int* arr = malloc(100 * sizeof(int)); if (arr == NULL) { perror("内存分配失败"); exit(EXIT_FAILURE); } ``` 2. **避免内存操作越界**: - 使用`sizeof`计算类型大小: ```c struct Data* data = malloc(10 * sizeof(*data)); // 直接引用目标变量 ``` 3. **工具辅助检测**: - Valgrind、AddressSanitizer检测内存泄漏和越界访问。 --- #### 八、总结 - **`malloc`**是动态内存分配的核心工具,赋予程序运行时灵活控制内存的能力。 - **`free`**确保内存资源的有效回收,避免资源泄漏。 - 二者共同构成C语言手动内存管理的基础,需严格遵循**分配-使用-释放**的闭环逻辑。 --- --相关问题--: 1. 如何检测C程序中的内存泄漏? 2. `malloc`与`calloc`在内存分配时有何区别? 3. 为什么频繁调用`malloc`会影响程序性能? 4. C++的`new/delete`与`malloc/free`有何本质差异?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值