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

printf格式化字符串加空格后,数组值为何出现异常?

C语言二维数组指针操作导致的异常值问题

原始代码

#include <stdio.h>
#include <stdlib.h>

typedef int board[8][8];


board * initBoard(void)
{
    board * b = malloc(sizeof(board));
    if (!b) { return b; }
    for (int i = 0; i < 8; i++){
        for (int j = 0; j < 8; j ++){
            *b[i][j] = 0;
        }
    }
    return b;
}

void toggle(board * b, int x, int y)
{
    if (*b[x][y] == 1){
        *b[x][y] = 0;
        return;
    }
    *b[x][y] = 1;
}

void dumpBoard(board * b)
{
    for (int i = 0; i < 8; i++){
        for (int j = 0; j < 8; j ++){
            printf("%d", *b[i][j]);
        }printf("\n");
    }
}

int main(void)
{
    board * b = initBoard();
    if (!b) { return EXIT_FAILURE; }
    dumpBoard(b);
    toggle(b, 3, 5);
    toggle(b, 7, 7);
    printf("\n");
    dumpBoard(b);
}

问题现象

这段代码初始化一个8×8的int二维数组,初始值全为0,打印后切换部分元素为1再打印,原本输出符合预期:

00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

00000000
00000000
00000000
00000100
00000000
00000000
00000000
00000001

但修改dumpBoard函数中的printf("%d", *b[i][j]);为printf("%d ", *b[i][j]);后,输出出现异常,第二行第二个位置(数组索引(1,1))出现了一个极大的随机数值:

0   0   0   0   0   0   0   0
0   540024864   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0

0   0   0   0   0   0   0   0
0   540024864   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   1   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   1

原因分析

问题核心是运算符优先级:[]的优先级高于*,所以*b[i][j]会被编译器解释为*(b[i][j])。

b是board*类型,而board是int[8][8]的别名,因此b[i]等价于*(b + i),也就是从b的地址偏移i * sizeof(board)个字节的位置。但我们只通过malloc(sizeof(board))分配了一个8×8数组的空间,当i >= 1时,b[i]已经指向了堆内存中超出分配范围的区域,属于越界访问,这是C语言中的未定义行为。

之前没出现明显问题是因为未定义行为的表现不确定,可能刚好越界的内存区域当时是0,或者紧凑的输出格式没暴露问题。修改printf格式后,内存布局发生变化,越界访问到了存储随机数值的内存区域,异常就显现出来了。

修正方法

需要先解引用b得到二维数组,再访问对应的行列,把所有*b[i][j]改成(*b)[i][j]。修正后的代码如下:

#include <stdio.h>
#include <stdlib.h>

typedef int board[8][8];


board * initBoard(void)
{
    board * b = malloc(sizeof(board));
    if (!b) { return b; }
    for (int i = 0; i < 8; i++){
        for (int j = 0; j < 8; j ++){
            (*b)[i][j] = 0;
        }
    }
    return b;
}

void toggle(board * b, int x, int y)
{
    if ((*b)[x][y] == 1){
        (*b)[x][y] = 0;
        return;
    }
    (*b)[x][y] = 1;
}

void dumpBoard(board * b)
{
    for (int i = 0; i < 8; i++){
        for (int j = 0; j < 8; j ++){
            printf("%d   ", (*b)[i][j]);
        }printf("\n");
    }
}

int main(void)
{
    board * b = initBoard();
    if (!b) { return EXIT_FAILURE; }
    dumpBoard(b);
    toggle(b, 3, 5);
    toggle(b, 7, 7);
    printf("\n");
    dumpBoard(b);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 15:58:17