C语言如何缩减数组未使用的预留内存,能否根据存储值调整元素占用空间?
问题解答
一、缩减预留未使用内存的可行性及操作方案
- 如果你继续使用当前栈上分配的固定大小数组(比如你代码里的
int arr[4][300]),该操作无法实现:栈内存的大小在编译阶段就已经固定,运行过程中无法动态调整预留空间的大小,多余的未使用空间会一直占用直到数组生命周期结束自动回收。 - 如果你切换为
malloc堆内存分配,该操作可以实现:你可以使用标准库函数realloc调整已分配堆内存块的大小,传入原堆指针和你需要的目标大小即可,多余的内存会被释放回堆空间。比如你预留了32字节仅使用24字节,直接调用realloc(原指针, 24)即可完成缩减。
注意:使用
realloc时需要先用临时指针接收返回值,避免realloc失败返回NULL导致原内存地址丢失,引发内存泄漏。
二、降低单个元素内存占用的方案
你的需求完全可以实现,只要你读取的数值范围匹配更小的存储类型即可:
- 如果你要存储的数值范围在
-128 ~ 127(有符号)或0 ~ 255(无符号),可以直接将int替换为1字节长度的signed char/unsigned char或者标准类型int8_t/uint8_t,单个元素的内存占用直接从4字节降到1字节,总内存占用直接缩减为原来的1/4。 - 如果数值范围更大但不超过
-32768 ~ 32767,可以使用2字节的int16_t,也能比原int省一半内存。
修改后的可运行代码示例
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <stdint.h> // 包含int8_t等标准定长类型定义 int main() { FILE *input = fopen("1.txt", "r"); // 改用堆分配1字节元素的4行300列数组,总大小仅4*300=1200字节,原int版本是4800字节 int8_t (*arr)[300] = malloc(4 * sizeof *arr); if (arr == NULL) { printf("内存分配失败\n"); return 1; } if (input == NULL) { printf("ERROR. Couldn't open the file.\n"); free(arr); return 1; } for (int i = 0; i < 300; i++) { // 读取的时候用int类型临时变量中转,避免fscanf写入长度不匹配 int tmp0, tmp1, tmp2, tmp3; fscanf(input, "%d %d %d %d", &tmp0, &tmp1, &tmp2, &tmp3); arr[0][i] = (int8_t)tmp0; arr[1][i] = (int8_t)tmp1; arr[2][i] = (int8_t)tmp2; arr[3][i] = (int8_t)tmp3; } fclose(input); // 如果后续确认实际只用前N列,可以用realloc缩减数组大小,比如只用200列的话: // int8_t (*tmp_arr)[200] = realloc(arr, 4 * sizeof *tmp_arr); // if (tmp_arr != NULL) arr = (void*)tmp_arr; int sze = 0; for (int i = 0; i < 300; i++) { for (int j = 0; j < 4; j++) { int val = arr[j][i]; if (abs(val) >= 1) sze += log10(abs(val)) + 1; else sze++; if (val < 0) sze++; } } printf("Size %d kB\n", sze); free(arr); // 堆内存使用完记得释放 return 0; }
注意事项
- 替换为小长度类型前一定要确认你读取的所有数值都在对应类型的取值范围内,否则会发生整数溢出,导致数据错误。
- 如果后续你需要调整数组的行数/列数,也可以完全改为动态计算大小后再分配内存,不需要预先预留多余空间,从根源上避免内存浪费。
内容的提问来源于stack exchange,提问作者Belen
相关产品推荐
相关产品推荐

