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

for循环执行中数组地址突变引发EXC_BAD_ACCESS错误求助

EXC_BAD_ACCESS错误排查与修复:C++生命游戏内存越界问题

在Mac系统VSCode搭配clang编译器环境下,代码第55行的for循环前12次执行正常,第13次时board变量内存地址从0x00007ff7bfeff310变为0x00007ff700000000,触发EXC_BAD_ACCESS错误。以下是问题分析与修复方案:

原始代码

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cstring>  // 补充memset所需头文件
using namespace std;

int *dead_state (int *board, int width, int height) {
    memset(board, 0, (height * width) * sizeof(int));
    return board;
}
int *random_state (int *board, int width, int height) {
    srand(time(0));
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            board[(x * width) + y] = rand() % 2;
        }
    }
    return board;
}
void render_board(int *board, int width, int height) {
    for (int x = 0; x < width + 2; x++) {
        cout << "-";
    }
    cout << endl;
    for (int x = 0; x < width; x++)  {
        cout << "|";
        for (int y = 0; y < height; y++) {
            cout << ((board[(x * width) + y]) ? "#" : " ");
        }
        cout << "|" << endl;
    }
    for (int x = 0; x < width + 2; x++) {
        cout << "-";
    }
    cout << endl;
}
int *next_board_state(int *board, int width, int height) {
    int new_board[width][height];
    int draw_board[width][height];
    dead_state(*new_board, width, height);
    dead_state(*draw_board, width, height);
    for (int x = 0; x < width * height; x++) {
        int alive = 0;
        //check right 3
        if (!(x % width == width - 1)) {
            alive += board[x + 1];
            if (!(x < width)){
                alive += board[x + 1 - width];
            }
            if (!(x >= width * height - width)) {
                alive += board[x + 1 + width];
            }
        }
        //check left 3
        if (!(x % width == 0)) {
            alive += board[x - 1];
            if (!(x < width)){
                alive += board[x - 1 - width];
            }
            if (!(x > width * height - width)) {
                alive += board[x - 1 + width];
            }
        }
        //check top
        if (!(x < width)){
            alive += board[x - width];
        }
        //check bottom
        if (!(x >= width * height - width)) {
            alive += board[x + width];
        }
        //change board states
        if (board[x] == 1) {
            if (alive == 2 || alive == 3) {
                *new_board[x] = 1;
            }
            else {
                *new_board[x] = 0;
            }
        }
        else {
            if (alive == 3) {
                *new_board[x] = 1;
            }
        }
        *draw_board[x] = alive;
    }
    //Assign new board to board
    for (int x = 0; x < width * height; x++) {
        board[x] = *new_board[x];
        if (x % width == 0) {
            cout << endl;
        }
        cout << *draw_board[x] << " ";
    }
    return board;
}

int main () {
    int width = 5, height = 5;
    int board[width][height];
    dead_state(*board, width, height);
    random_state(*board, width, height);
    render_board(*board, width, height);
    next_board_state(*board, width, height);
    render_board(*board, width, height);
    return 0;
}

问题根源分析

1. 二维数组与指针的错误转换

代码中多次将二维数组以*board的形式传递给函数,*board等价于board[0],仅指向二维数组的第一行,而非整个数组的起始地址。当函数通过该指针访问超出第一行的内存时,会导致越界。

2. 二维数组的错误下标访问

在next_board_state函数中,new_board和draw_board是二维数组,*new_board[x]的写法完全错误:

  • new_board[x]代表二维数组的第x行指针,当x超过height-1(比如width=5、height=5时,x=5就超出了行范围),会直接访问数组外的内存,触发地址异常。
  • 正确的做法是将一维索引x转换为二维坐标:row = x / height,col = x % height,再通过new_board[row][col]访问。

3. 数组索引计算逻辑错误

random_state和render_board中使用x * width + y计算一维索引,不符合行优先存储的规则。对于int board[width][height],行索引x对应的一维偏移应为x * height + y,否则当width≠height时会直接越界。

修复后的代码

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cstring>
using namespace std;

int *dead_state (int *board, int total_size) {
    memset(board, 0, total_size * sizeof(int));
    return board;
}

int *random_state (int *board, int width, int height) {
    srand(time(0));
    int total = width * height;
    for (int i = 0; i < total; i++) {
        board[i] = rand() % 2;
    }
    return board;
}

void render_board(int *board, int width, int height) {
    // 打印顶部边框
    for (int i = 0; i < width + 2; i++) {
        cout << "-";
    }
    cout << endl;

    // 打印每行内容
    for (int x = 0; x < width; x++)  {
        cout << "|";
        for (int y = 0; y < height; y++) {
            int idx = x * height + y;
            cout << (board[idx] ? "#" : " ");
        }
        cout << "|" << endl;
    }

    // 打印底部边框
    for (int i = 0; i < width + 2; i++) {
        cout << "-";
    }
    cout << endl;
}

int *next_board_state(int *board, int width, int height) {
    int total = width * height;
    int new_board[width][height];
    int draw_board[width][height];

    // 初始化新数组为死状态
    dead_state(&new_board[0][0], total);
    dead_state(&draw_board[0][0], total);

    for (int i = 0; i < total; i++) {
        int alive = 0;
        int x = i / height;   // 行索引
        int y = i % height;   // 列索引

        // 检查右侧邻居
        if (y < height - 1) {
            alive += board[i + 1];
            if (x > 0) alive += board[i + 1 - height];
            if (x < width - 1) alive += board[i + 1 + height];
        }

        // 检查左侧邻居
        if (y > 0) {
            alive += board[i - 1];
            if (x > 0) alive += board[i - 1 - height];
            if (x < width - 1) alive += board[i - 1 + height];
        }

        // 检查上方邻居
        if (x > 0) {
            alive += board[i - height];
        }

        // 检查下方邻居
        if (x < width - 1) {
            alive += board[i + height];
        }

        // 更新新状态
        if (board[i] == 1) {
            new_board[x][y] = (alive == 2 || alive == 3) ? 1 : 0;
        } else {
            new_board[x][y] = (alive == 3) ? 1 : 0;
        }
        draw_board[x][y] = alive;
    }

    // 将新状态复制回原数组,并打印邻居数量
    for (int i = 0; i < total; i++) {
        int x = i / height;
        int y = i % height;
        board[i] = new_board[x][y];
        if (y == 0) cout << endl;
        cout << draw_board[x][y] << " ";
    }
    cout << endl;

    return board;
}

int main () {
    int width = 5, height = 5;
    int board[width][height];
    int total = width * height;

    dead_state(&board[0][0], total);
    random_state(&board[0][0], width, height);
    render_board(&board[0][0], width, height);
    next_board_state(&board[0][0], width, height);
    render_board(&board[0][0], width, height);

    return 0;
}

关键修复点

  • 传递二维数组时,使用&board[0][0]明确传递整个数组的起始地址。
  • 统一一维索引与二维坐标的转换逻辑,避免越界访问。
  • 修正dead_state函数参数,直接传递总元素数,减少计算错误。
  • 调整邻居检查的边界条件,基于行列索引判断而非一维索引,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 12:02:03