未初始化读取malloc()分配字节是否为UB?malloc缓冲区合法操作有哪些?
malloc(N)分配缓冲区后的合法操作与未定义行为说明
一、合法操作说明
当malloc(N)成功返回非NULL指针时,该指针指向一块大小至少为N字节、满足对齐要求的内存块,以下是合法操作:
写入最多N字节数据:可以向缓冲区的前N字节写入任意符合类型要求的数据。注意:虽然实际分配的内存可能比N大,但超出N的部分属于未被分配的额外空间,写入或读取这部分均为未定义行为,绝对不能依赖。
示例代码:#include <stdlib.h> int main() { int *nums = malloc(3 * sizeof(int)); // 分配至少12字节 if (nums != NULL) { nums[0] = 10; nums[1] = 20; nums[2] = 30; // 合法写入12字节 } free(nums); return 0; }读取已初始化的字节:当缓冲区的字节被写入(初始化)后,可以安全读取这些已初始化的内容。
示例代码:#include <stdlib.h> #include <stdio.h> int main() { char *buf = malloc(10); if (buf != NULL) { buf[0] = 'a'; buf[1] = 'b'; printf("%c%c\n", buf[0], buf[1]); // 合法读取已初始化的字符 } free(buf); return 0; }使用
free()释放内存:必须通过free()函数释放malloc分配的缓冲区,释放后该指针变为野指针,不能再访问指向的内存。
示例代码:#include <stdlib.h> int main() { void *mem = malloc(50); if (mem != NULL) { free(mem); // 合法释放 // mem = NULL; // 建议将指针置空,避免野指针误用 } return 0; }使用
realloc()调整内存大小:可以通过realloc()修改缓冲区的大小,成功返回的新指针指向的内存会保留原缓冲区中前min(原大小, 新大小)字节的有效数据。
示例代码:#include <stdlib.h> int main() { int *arr = malloc(2 * sizeof(int)); if (arr != NULL) { arr[0] = 1; arr[1] = 2; // 扩容为4个int的空间 int *new_arr = realloc(arr, 4 * sizeof(int)); if (new_arr != NULL) { arr = new_arr; arr[2] = 3; arr[3] = 4; // 合法写入新扩容的空间 } free(arr); } return 0; }
二、未初始化读取的行为判定
未初始化就读取malloc()分配的字节属于未定义行为(UB)。
C语言标准明确规定,读取未初始化对象的值是未定义行为——编译器对此没有固定处理逻辑:可能返回随机的垃圾值,可能导致程序崩溃,甚至可能因为编译器的优化策略,出现完全不符合预期的逻辑错误(比如编译器假设未初始化的值不会被读取,直接优化掉相关读取代码)。
示例(存在未定义行为的代码):
#include <stdlib.h> #include <stdio.h> int main() { int *val = malloc(sizeof(int)); if (val != NULL) { printf("%d\n", *val); // 非法:读取未初始化的内存 } free(val); return 0; }
内容的提问来源于stack exchange,提问作者doliphin
相关产品推荐
相关产品推荐

