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

控制台无法输出,程序退出码-1073741819问题求助

问题描述

跟随One Lone Coder的控制台渲染教程编写代码后,在Visual Studio中按Ctrl+F5运行时控制台无任何输出,调试窗口显示程序以退出码-1073741819终止。代码如下:

#include <iostream>
#include <Windows.h>
#include <cmath>
#include<chrono>
using namespace std;


int nscreenwidth = 120;
int nscreenheight = 40;
float fPlayerX = 8.0f;
float fPlayerY = 8.0f;
float fPlayerA = 0.0f;

int nMapHeight = 16;
int nMapWidth = 16;
float fFOV = 3.1415 / 4.0;

int main() {
    wchar_t* screen = new wchar_t[nscreenheight * nscreenwidth];
    HANDLE hconsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    SetConsoleActiveScreenBuffer(hconsole);
    DWORD dwBytesWritten = 0;
    wstring map;


    map += L"################";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"################";

    auto tp1 = chrono::system_clock::now();
    auto tp2 = chrono::system_clock::now();


    while (1) {
        tp2 = chrono::system_clock::now();
        chrono::duration<float> elapsedtime = tp2 - tp1;
        tp1 = tp2;
        float fElapsedTime = elapsedtime.count();

        if (GetAsyncKeyState((unsigned short)'A') & 0x8000)
            fPlayerA -= (0.1f * fElapsedTime);
        if (GetAsyncKeyState((unsigned short)'D') & 0x8000)
            fPlayerA += (0.1f * fElapsedTime);
        for (int x = 0; x < nscreenwidth; x++) {
            float fDistanceWall = 0;
            float fOffsetfov = (fPlayerA - fFOV / 2.0) + (((float)x / (float)nscreenwidth) * fFOV);
            float fUnitVecX = sinf(fOffsetfov);
            float fUnitVecy = cosf(fOffsetfov);
            bool bHitWall = false;
            while (!bHitWall && fDistanceWall < 16.0) {
                fDistanceWall += 0.1;
                int nTestX = (int)(fPlayerX + (fUnitVecX * fDistanceWall));
                int nTestY = (int)(fPlayerY + (fUnitVecy * fDistanceWall));
                if (nTestX < 0 || nTestX >= nMapWidth || nTestY >= nMapHeight) {
                    bHitWall = true;
                    fDistanceWall = 16.0f;
                }
                else if (map[nTestX * nMapWidth + nTestY] == '#') {
                    bHitWall = true;
                }
            }
            int nCeiling = (float)(nscreenheight / 2.0) - nscreenheight / ((float)fDistanceWall);
            int nFloor = nscreenheight - nCeiling;
            for (int y = 0; y < nscreenheight; y++) {
                if (y > nCeiling) {
                    screen[x * nscreenwidth + y] = ' ';
                }
                else if (y < nFloor) {
                    if(fDistanceWall <= 16.0/4.0)
                        screen[x * nscreenwidth + y] = '#';
                    else if (fDistanceWall < 16.0 / 2.0)
                        screen[x * nscreenwidth + y] = '.';
                    else {
                        screen[x * nscreenwidth + y] = ' ';
                    }
                }
            }
        }


        screen[nscreenheight * nscreenwidth - 1] = '\\0';
        WriteConsoleOutputCharacter(hconsole, screen, nscreenwidth * nscreenheight, { 0,0 }, &dwBytesWritten);
    }
    return 0;
} 
问题原因
  • 数组越界访问(崩溃核心原因):地图索引计算错误,map[nTestX * nMapWidth + nTestY]不符合地图行优先的存储逻辑。地图按行拼接,每行含nMapWidth个字符,正确索引应为行号×宽度+列号即nTestY * nMapWidth + nTestX,原代码颠倒X/Y顺序,导致访问超出map有效内存范围,触发内存错误直接崩溃。
  • 屏幕缓冲区索引错误:screen[x * nscreenwidth + y]不符合屏幕缓冲区行优先存储逻辑,正确索引应为y * nscreenwidth + x,原索引方式会导致越界或渲染混乱。
  • 宽字符终止符错误:screen[nscreenheight * nscreenwidth - 1] = '\\0';多了一个反斜杠,且未使用宽字符字面量L'\0',可能引发字符串处理异常。
  • 未初始化屏幕缓冲区:动态分配的screen数组未初始化,内存存在随机值,引发未定义行为。
  • 旋转速度过慢:0.1f * fElapsedTime的旋转系数太小,导致A/D键旋转效果几乎不可见,影响交互体验。
修复后的代码
#include <iostream>
#include <Windows.h>
#include <cmath>
#include<chrono>
#include <cstring> // 用于memset
using namespace std;

int nscreenwidth = 120;
int nscreenheight = 40;
float fPlayerX = 8.0f;
float fPlayerY = 8.0f;
float fPlayerA = 0.0f;

int nMapHeight = 16;
int nMapWidth = 16;
float fFOV = 3.1415 / 4.0;

int main() {
    wchar_t* screen = new wchar_t[nscreenheight * nscreenwidth];
    // 初始化屏幕缓冲区为空格,避免未定义行为
    memset(screen, ' ', nscreenheight * nscreenwidth * sizeof(wchar_t));
    
    HANDLE hconsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    SetConsoleActiveScreenBuffer(hconsole);
    DWORD dwBytesWritten = 0;
    wstring map;

    map += L"################";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"################";

    auto tp1 = chrono::system_clock::now();
    auto tp2 = chrono::system_clock::now();

    while (1) {
        tp2 = chrono::system_clock::now();
        chrono::duration<float> elapsedtime = tp2 - tp1;
        tp1 = tp2;
        float fElapsedTime = elapsedtime.count();

        // 提高旋转速度,让操作更直观
        if (GetAsyncKeyState((unsigned short)'A') & 0x8000)
            fPlayerA -= 2.0f * fElapsedTime;
        if (GetAsyncKeyState((unsigned short)'D') & 0x8000)
            fPlayerA += 2.0f * fElapsedTime;

        for (int x = 0; x < nscreenwidth; x++) {
            float fDistanceWall = 0;
            float fOffsetfov = (fPlayerA - fFOV / 2.0) + (((float)x / (float)nscreenwidth) * fFOV);
            float fUnitVecX = sinf(fOffsetfov);
            float fUnitVecY = cosf(fOffsetfov);
            bool bHitWall = false;

            while (!bHitWall && fDistanceWall < 16.0) {
                fDistanceWall += 0.1;
                int nTestX = (int)(fPlayerX + fUnitVecX * fDistanceWall);
                int nTestY = (int)(fPlayerY + fUnitVecY * fDistanceWall);

                // 完善边界检查,包含nTestY < 0的情况
                if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight) {
                    bHitWall = true;
                    fDistanceWall = 16.0f;
                }
                // 修正地图索引:行号(nTestY) × 宽度 + 列号(nTestX)
                else if (map[nTestY * nMapWidth + nTestX] == '#') {
                    bHitWall = true;
                }
            }

            int nCeiling = static_cast<float>(nscreenheight / 2.0) - nscreenheight / static_cast<float>(fDistanceWall);
            int nFloor = nscreenheight - nCeiling;

            for (int y = 0; y < nscreenheight; y++) {
                // 修正屏幕缓冲区索引:行号(y) × 宽度 + 列号(x)
                if (y < nCeiling) {
                    screen[y * nscreenwidth + x] = L' ';
                }
                else if (y > nFloor) {
                    screen[y * nscreenwidth + x] = L' ';
                }
                else {
                    if (fDistanceWall <= 16.0 / 4.0)
                        screen[y * nscreenwidth + x] = L'#';
                    else if (fDistanceWall < 16.0 / 2.0)
                        screen[y * nscreenwidth + x] = L'.';
                    else
                        screen[y * nscreenwidth + x] = L' ';
                }
            }
        }

        // 设置正确的宽字符终止符
        screen[nscreenheight * nscreenwidth - 1] = L'\0';
        WriteConsoleOutputCharacter(hconsole, screen, nscreenwidth * nscreenheight, { 0,0 }, &dwBytesWritten);
    }

    // 释放动态分配的内存,避免内存泄漏
    delete[] screen;
    return 0;
}
修复要点
  1. 修正地图索引:将nTestX * nMapWidth + nTestY改为nTestY * nMapWidth + nTestX,匹配地图行优先存储结构,解决数组越界问题。
  2. 修正屏幕缓冲区索引:将x * nscreenwidth + y改为y * nscreenwidth + x,确保正确访问屏幕每个字符位置。
  3. 初始化屏幕缓冲区:使用memset将screen数组初始化为空格,避免未定义行为。
  4. 修复宽字符终止符:将'\\0'改为L'\0',符合宽字符字符串要求。
  5. 调整旋转速度:把旋转系数从0.1f提升至2.0f,让A/D键旋转效果更明显。
  6. 添加内存释放:在程序结束前添加delete[] screen;,释放动态分配的内存,避免内存泄漏。
  7. 完善边界检查:在地图碰撞检测中添加nTestY < 0的判断,防止负索引越界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:02:02