You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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语言的内存分为栈内存和堆内存两类,分配逻辑不同:

  1. 栈内存

    • 由编译器自动分配和释放,用于存储局部变量、函数参数等。
    • 大小固定,编译时确定,超出会触发栈溢出错误。
    • 示例:代码中的int n、int k均为栈上变量。
  2. 堆内存

    • 需通过malloc/calloc/realloc手动申请,使用完必须用free释放,生命周期由程序员控制。
    • 大小灵活,运行时向操作系统申请,不释放会导致内存泄漏。
    • calloc细节:calloc(num, size)分配num * size字节内存,并将所有字节初始化为0;malloc则只分配内存不初始化。
    • 注意:堆内存分配可能失败,需检查返回值是否为NULL。

内容的提问来源于stack exchange,提问作者Samarth Goyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 15:05:09