C语言内存分配原理解析及数字方阵代码calloc跨编译器异常排查
问题描述
作为编程新手,我正在解决一个编程问题:输入整数n,打印特定的递减数字方阵。例如输入5时,输出9行9列的方阵如下:
5 5 5 5 5 5 5 5 5
5 4 4 4 4 4 4 4 5
5 4 3 3 3 3 3 4 5
5 4 3 2 2 2 3 4 5
5 4 3 2 1 2 3 4 5
5 4 3 2 2 2 3 4 5
5 4 3 3 3 3 3 4 5
5 4 4 4 4 4 4 4 5
5 5 5 5 5 5 5 5 5
我采用数组结合反复增减元素的思路编写了C语言代码,该代码在Visual Studio Code中可正常运行,但在在线编译器及其他测试编译器中无法正常工作,怀疑是calloc使用有误。同时想了解C语言中内存分配的工作原理。代码如下:
#include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> int main() { int n; scanf("%d", &n); // Complete the code to print the pattern. int *arr; int k = 1; arr = calloc(2 * n - 1, sizeof(char)); for (int i = 0; i < 2 * n - 1; i++) { *(arr + i) = n; } do { for (int i = 0; i < 2 * n - 1; i++) { printf("%d ", arr[i]); } printf("\n"); for (int i = k; i < 2 * n - 1 - k; i++) { arr[i] = arr[i] - 1; } k++; } while (k <= n); k = n - 1; for (int j = 1; j < n; j++) { for (int i = k; i < 2 * n - 1 - k; i++) { arr[i]++; } k--; for (int i = 0; i < 2 * n - 1; i++) { printf("%d ", arr[i]); } printf("\n"); } return 0; }
错误原因分析
代码的核心问题是内存分配的类型不匹配:
- 声明的
int *arr指向int类型数组,但calloc(2 * n - 1, sizeof(char))仅为每个元素分配1字节内存(char通常占1字节),而int类型通常占4字节。 - 通过
arr[i]访问或赋值时,会读取/写入4字节数据,超出了分配的内存范围,触发内存越界访问,属于未定义行为。不同编译器环境对内存越界的处理不同,VS Code中可能未触发崩溃,但其他环境会直接报错。
修正后的代码
将calloc的第二个参数改为sizeof(int)即可解决内存不匹配问题,同时优化冗余头文件和逻辑:
#include <stdio.h> #include <stdlib.h> int main() { int n; scanf("%d", &n); int *arr; int size = 2 * n - 1; int k = 1; // 分配int类型数组的内存,同时检查分配是否成功 arr = calloc(size, sizeof(int)); if (!arr) { fprintf(stderr, "内存分配失败\n"); return 1; } // 初始化数组所有元素为n for (int i = 0; i < size; i++) { arr[i] = n; } // 打印上半部分(含中间行) do { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); if (k >= n) break; // 避免最后一次无效的数组修改 for (int i = k; i < size - k; i++) { arr[i] -= 1; } k++; } while (k <= n); // 打印下半部分 k = n - 2; // 中间行已打印,从n-2开始调整数组 for (int j = 1; j < n; j++) { for (int i = k; i < size - k; i++) { arr[i] += 1; } k--; for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } free(arr); // 手动释放堆内存,避免内存泄漏 return 0; }
C语言内存分配核心原理
C语言的内存分为栈内存和堆内存两类,分配逻辑不同:
栈内存
- 由编译器自动分配和释放,用于存储局部变量、函数参数等。
- 大小固定,编译时确定,超出会触发栈溢出错误。
- 示例:代码中的
int n、int k均为栈上变量。
堆内存
- 需通过
malloc/calloc/realloc手动申请,使用完必须用free释放,生命周期由程序员控制。 - 大小灵活,运行时向操作系统申请,不释放会导致内存泄漏。
calloc细节:calloc(num, size)分配num * size字节内存,并将所有字节初始化为0;malloc则只分配内存不初始化。- 注意:堆内存分配可能失败,需检查返回值是否为
NULL。
- 需通过
内容的提问来源于stack exchange,提问作者Samarth Goyal
相关产品推荐
相关产品推荐

