简体   繁体   English

C++:添加一个逻辑上正确的 if 语句使我的程序崩溃

[英]C++: Adding a logically correct if statement crashes my program

I am a novice and I've run into a problem I can't seem to fix.我是新手,遇到了一个我似乎无法解决的问题。 Namely, I have these two seperate working blocks of code, yet if I use both of them the program crashes (returning an error code of 3221225477).也就是说,我有这两个独立的工作代码块,但是如果我同时使用它们,程序就会崩溃(返回错误代码 3221225477)。

#include <conio.h>
#include <iostream>
#include <string>
#include <windows.h>
#include <chrono>
#include <thread>
#include <vector>
#include <time.h>

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define ENTER 13

using namespace std;

struct set {
int speed=0;
bool obs=0;
} settings;

void gotoyx( int y, int x ) { //moves the console cursor
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle( STD_OUTPUT_HANDLE ), coord);
}

void setup() { //used to determine the snake's speed, expressed as delay between movement
int c = 0;
string o1=">SLOW", o2=" MEDIUM", o3=" FAST";
while(settings.speed==0)
{
    c = 0;
    gotoyx(c, c); //sets cursor at top-left
    cout << "Please choose your speed setting:\n"<< o1 << endl << o2 << endl << o3 << endl;
    switch((c=getch())) {
    case KEY_UP:
        if(o2.at(0)=='>'){
            o1[0]='>';
            o2[0]=' ';
        }
        else if(o3.at(0)=='>'){
            o2[0]='>';
            o3[0]=' ';
        }
        break;
    case KEY_DOWN:
        if(o1.at(0)=='>'){
            o2[0]='>';
            o1[0]=' ';
        }
        else if(o2.at(0)=='>'){
            o3[0]='>';
            o2[0]=' ';
        }
        break;
    case ENTER:
        if(o1.at(0)=='>') {
            cout << "You chose SLOW.\n";
            settings.speed=160; 
        }
        else if(o2.at(0)=='>') {
            cout << "You chose MEDIUM.\n";
            settings.speed=120;
        }
        else {
            cout << "You chose FAST.\n";
            settings.speed=80;
        }
        settings.obs=1;
        cout << "Press a key to continue.";
        getch();
        break;
    default:
        break;
    }
}
}

void draw_border() {
for(int i=0; i<80; i++){ //80 fills screen vertically - TOP
    cout<<"#";
}
for(int i=0; i<23; i++){ //25 fills screen horizontally (2 used for top and bottom)
    cout<<"#";
    for(int i=0; i<78; i++){
    cout<<" ";
    }
    cout<<"#";
}
for(int i=0; i<80; i++){ //80 fills screen vertically - BOTTOM
    cout<<"#";
}
}

void ShowConsoleCursor(bool showFlag) { //blinking-underscore-with-console
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);

CONSOLE_CURSOR_INFO     cursorInfo;

GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = showFlag; // set the cursor visibility
SetConsoleCursorInfo(out, &cursorInfo);
  }

int keypad(int out){                                        //reads arrow keys during game
    if (GetAsyncKeyState(VK_UP) & 0x8000 && out!=1 ) {  //MSB set if currently pressed
        out=0;                                          //if nothing is pressed it returns
    }                                                   //the last pressed button
    else if (GetAsyncKeyState(VK_DOWN) & 0x8000 && out!=0) {
        out=1;
    }
    else if (GetAsyncKeyState(VK_LEFT) & 0x8000 && out!=3) {
        out=2;
    }
    else if (GetAsyncKeyState(VK_RIGHT) & 0x8000 && out!=2) {
        out=3;
    }
    return out;                                         
}

int main() {
ShowConsoleCursor(false);                               //disable blinking console cursor
setup();
int tmp=0, cntr_g=0, cntr_o=0;
system("cls");                                          //clear screen after inital setup
draw_border();
gotoyx(tmp, tmp);                                       //using cursor to scroll to console top
vector<vector<int>> snake_pos;                          //tracks snake location
snake_pos.emplace(snake_pos.begin(), std::initializer_list<int>{13,40});
int y = snake_pos[0][0];                                //Y coordinate of snake head
int x = snake_pos[0][1];                                //X coordinate of snake head
gotoyx(y, x);
cout<<"*";
int key, boost_y, boost_x, obstacle_y, obstacle_x;
bool b_flag=0;
vector<vector<int>> boost (1, vector<int>(2, 0));
vector<vector<int>> obstacle (1, vector<int>(2, 0));
while(1){
    key=keypad(key);
    if (key==0) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y-1, x});
    }
    else if (key==1) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y+1, x});
    }
    else if (key==2) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y, x-1});
    }
    else if (key==3) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y, x+1});
    }

    y = snake_pos[0][0]; x = snake_pos[0][1];           //updating snake head coordinates

    if (y==0 | y==24 | x==0 | x==80 ) {                 //checking whether player hit wall
        return 0;
    }
    for (tmp=1; tmp!=snake_pos.size()-1; ++tmp) {       //checking whether player hit self
        if (y==snake_pos[tmp][0] && x==snake_pos[tmp][1]) {
            return 0;
        }
    }

    //check if obstacle was hit [not here yet]

    ++cntr_g;                                           //generating growth boost block
    if (cntr_g==settings.speed/5) {
        label_growth:
        srand(time(NULL));
        boost_x=(rand()%78)+1;
        boost_y=(rand()%23)+1;
        for (tmp=0; tmp!=snake_pos.size()-1; ++tmp) {
            if (boost_y==snake_pos[tmp][0] && boost_x==snake_pos[tmp][1]) {
                goto label_growth;
            }
        }
        gotoyx(boost_y, boost_x); cout<<"O";
        boost.emplace_back(std::initializer_list<int> {boost_y, boost_x});
        cntr_g=0;
    }

    /*
    ++cntr_o;                                               //generating obstacle block
    if ((cntr_o==settings.speed/4) && (settings.obs==1)) {  //also check if obs enabled
        label_obstacle:
        srand(time(NULL));
        obstacle_x=(rand()%78)+1;
        obstacle_y=(rand()%23)+1;
        for (tmp=0; tmp!=snake_pos.size()-1; ++tmp) {       //check overlap with snake
            if (obstacle_y==snake_pos[tmp][0] && obstacle_x==snake_pos[tmp][1]) {
                goto label_obstacle;
            }
        }
        for (tmp=0; tmp!=boost.size()-1; ++tmp) {           //check overlap with boosts
            if (obstacle_y==boost[tmp][0] && obstacle_x==boost[tmp][1]) {
                goto label_obstacle;
            }
        }
        gotoyx(obstacle_y, obstacle_x); cout<<"X";
        obstacle.emplace_back(std::initializer_list<int> {obstacle_y, obstacle_x});
        cntr_o=0;
    }*/

    gotoyx(y, x); cout<<"*"; b_flag=0;                  //updating graphics for new snake
    for (tmp=0; tmp!=boost.size()-1; ++tmp) {           
        if (y==boost[tmp][0] && x==boost[tmp][1]) {
            boost.erase(boost.begin()+tmp);
            b_flag=1;
            break;
        }
    }
    if (b_flag==0){                                     //if snake didn't grow, last block stays
        gotoyx(snake_pos.back()[0], snake_pos.back()[1]); cout<<" ";
        snake_pos.pop_back();
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(settings.speed));
}

return 0;
}

Namely, the problem is with the if statement for the growth block portion, and the obstacle block portion.即,问题在于增长块部分和障碍块部分的 if 语句。 The program(game) works as intended when one of them is commented out, but doesn't if both of them are left in. In fact, even just leaving in the cntr_o++;当其中一个被注释掉时,程序(游戏)按预期工作,但如果两个都被保留,则不会。事实上,即使只是离开cntr_o++; without the following if statement is enough to crash it.如果没有以下 if 语句就足以让它崩溃。

Compilers are fickle things.编译器是善变的东西。 Your code could be incorrect and still not crash due to the happenstance way that memory is laid out by the compiler.由于编译器布置内存的偶然方式,您的代码可能不正确并且仍然不会崩溃。 This is a result of "undefined behavior".这是“未定义行为”的结果。 Undefined behavior can cause your program to crash, but it might also have no observable effects.未定义的行为可能会导致您的程序崩溃,但它也可能没有可观察到的影响。

While your code is a bit too disorganized for casual debugging, you may find that a debugger may help.虽然您的代码对于随意调试来说有点过于杂乱无章,但您可能会发现调试器可能会有所帮助。 If you're able to use clang, I suggest add -Wall -Wextra and -fsanitize=address -fsanitize=undefined to catch some of the simpler issues.如果您能够使用 clang,我建议添加 -Wall -Wextra 和 -fsanitize=address -fsanitize=undefined 来解决一些更简单的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM