C语言动态内存疑问:越界访问无报错、sizeof未显示实际大小
问题描述
代码示例
int main(){ printf("%lu\n",(1 * sizeof(int))); int* hello=malloc(1 * sizeof(int)); hello[1000000]=10; printf("%d\n",hello[1000000]); printf("%lu\n", sizeof(hello)); int* goodbye=malloc(100 * sizeof(int)); printf("%lu\n",sizeof(goodbye)); hello=goodbye; printf("%lu\n",sizeof(hello)); hello=realloc(hello,20); hello[1]=0; printf("%lu\n",sizeof(hello)); }
程序输出
4 10 8 8 8 8
困惑点
- 只为
hello分配了4字节内存,却能访问hello[1000000]且无任何警告或错误; - 尝试通过将
hello赋值为goodbye、调用realloc调整大小,但sizeof始终返回8,无法反映数组实际大小; - 想要实现动态大小的
int数组,不知道哪里出错了。
问题解答
1. 越界访问为何没报错?
C语言本身不做数组边界检查,这是出于性能优先的设计。你访问hello[1000000]属于未定义行为——这次碰巧能读写成功,只是因为那块内存暂时没被程序或系统占用/保护,并不是合法操作。如果那块内存被其他数据占用,你的写入会破坏原有数据,导致程序崩溃、数据错乱等不可预测的后果。
编译器默认不会主动检测这种越界,但可以开启编译警告(比如GCC的-Wall -Wextra),部分情况下能发现明显的越界问题,但无法覆盖所有场景。
2. 为什么sizeof(hello)始终返回8?
hello是指针变量,不是数组。在64位系统中,指针的大小固定为8字节(32位系统是4字节),sizeof计算的是指针本身的大小,而非它指向的内存块的大小。
C语言不会自动跟踪动态分配内存的大小,malloc/realloc也不会把这个信息存在指针里,你需要手动用单独变量记录动态数组的实际大小。
3. 如何实现动态大小的int数组?
要实现动态数组,需要同时维护指针和当前数组的大小/容量:
示例代码:
#include <stdio.h> #include <stdlib.h> int main(){ // 动态数组的指针、当前元素个数、容量(用于扩容优化) int* arr = NULL; size_t count = 0; size_t capacity = 0; // 初始分配,容量设为4个int capacity = 4; arr = malloc(capacity * sizeof(int)); if(arr == NULL){ perror("malloc failed"); return 1; } // 添加元素,元素个数达到容量时扩容 for(int i=0; i<10; i++){ if(count >= capacity){ // 扩容为原来的2倍 capacity *= 2; int* temp = realloc(arr, capacity * sizeof(int)); if(temp == NULL){ perror("realloc failed"); free(arr); return 1; } arr = temp; } arr[count] = i; count++; } // 输出数组信息 printf("数组元素:"); for(size_t i=0; i<count; i++){ printf("%d ", arr[i]); } printf("\n当前元素个数:%zu,当前容量:%zu\n", count, capacity); // 释放内存,避免泄漏 free(arr); arr = NULL; return 0; }
核心要点:
- 用单独变量记录数组的实际元素个数和容量(容量是已分配内存能容纳的最大元素数,个数是当前已使用的元素数);
- 每次添加元素前检查是否需要扩容,用
realloc重新分配内存时,必须检查返回值(失败会返回NULL,此时原有内存不会被释放); - 不再使用动态数组时,一定要用
free释放内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Alejandro Aescliptus
相关产品推荐
相关产品推荐

