如何在C语言函数中使用二级指针实现指定对齐要求的内存分配
核心错误点
- 你直接修改了函数形参
ptr_addr的值:ptr_addr是void**类型的局部形参,是外部传入的&ptr_2的拷贝,直接修改它的指向不会影响外部的ptr_2变量,所以调用后ptr_2还是原来的&a地址。要修改外部指针的值,需要解引用二级指针,也就是修改*ptr_addr的取值。 - 没有实现地址对齐逻辑:当前的
malloc调用既没有分配满足要求的内存大小,也没有做地址对齐的计算,就算正确赋值给*ptr_addr也不满足对齐要求。
实现思路
对齐内存分配的核心逻辑是多申请额外的空间用于地址偏移,同时要保存malloc返回的原始地址,方便后续内存释放:
- 先做参数合法性校验:
alignment必须是2的整数次幂、不能为0,size也不能为0,校验不合法直接返回非0错误码。 - 计算总申请内存大小:需要额外申请
alignment - 1字节的空间用于地址对齐偏移,再加sizeof(void*)字节的空间用来存储malloc返回的原始地址,总大小为size + alignment - 1 + sizeof(void*)。 - 调用
malloc申请总大小的内存,记为original_ptr,如果申请失败返回非0错误码。 - 计算对齐后的地址:先将原始地址偏移
sizeof(void*)(预留存储原始地址的空间),再向上对齐到alignment的倍数:uintptr_t addr = (uintptr_t)original_ptr + sizeof(void*); uintptr_t aligned_addr = (addr + alignment - 1) & ~(alignment - 1); void* aligned_ptr = (void*)aligned_addr; - 将原始地址存储在对齐地址的前一个指针大小的位置:
*( (void**)aligned_ptr - 1 ) = original_ptr; - 将对齐后的地址赋值给
*ptr_addr,返回0表示分配成功。
示例实现代码
#include <stdint.h> #include <stdlib.h> int block_alloc(void ** ptr_addr, size_t alignment, size_t size) { // 参数校验 if (ptr_addr == NULL || alignment == 0 || size == 0) { return -1; } // 可选校验:要求alignment是2的幂 if ((alignment & (alignment - 1)) != 0) { return -1; } size_t total_size = size + alignment - 1 + sizeof(void*); void* original_ptr = malloc(total_size); if (original_ptr == NULL) { return -1; } // 计算对齐地址 uintptr_t addr = (uintptr_t)original_ptr + sizeof(void*); uintptr_t aligned_addr = (addr + alignment - 1) & ~(alignment - 1); void* aligned_ptr = (void*)aligned_addr; // 存储原始地址 *((void**)aligned_ptr - 1) = original_ptr; // 赋值给外部指针 *ptr_addr = aligned_ptr; return 0; }
注意事项
后续释放该内存时不能直接free(aligned_ptr),需要先取出存储的原始地址再释放,示例释放逻辑:
void block_free(void* aligned_ptr) { if (aligned_ptr == NULL) return; void* original_ptr = *((void**)aligned_ptr - 1); free(original_ptr); }
内容的提问来源于stack exchange,提问作者Stressed Noob
相关产品推荐
相关产品推荐

