变量事件的值当不对它们进行操作时

时间:2021-02-07 15:21:26

I have this code:

我有这个代码:

#include <iostream>
#include<cstdio>
#include<conio.h>
#include<windows.h>
#define BOARDSIZE 3
using namespace std;

int board[BOARDSIZE][BOARDSIZE];
int cnt = 0;
int minCount = BOARDSIZE*BOARDSIZE;

void boardSwitch(int x, int y){
    for(int i = x-1; i <= x+1; i++){
        for(int j = y-1; j <= y+1; j++){
            if((i>=0) && (j>=0)){
                board[i][j] = board[i][j] ^ 1;
            }
        }
    }
}

bool isOn(){
    int i, j;

    for(i = 0; i < BOARDSIZE; i++){
        for(j = 0; j < BOARDSIZE; j++){
            if(!board[i][j]){
                return 0;
            }
        }
    }
    return 1;
}

void boardDisp(){
    for(int i = 0; i <BOARDSIZE; i++){
        for(int j = 0; j < BOARDSIZE; j++){
            cout<<board[i][j]<<" ";
        }
        cout<<endl;
    }
}

void turn(int x){
    int i, j;

    j = x%BOARDSIZE;
    i = (x-j)/BOARDSIZE;
    if(x == 0){
        cnt = 0;
    }
    for(int k = 0; k <=1; k++){
        printf("%d \n", cnt);
        cout<<i<<" "<<j<<" cnt = "<<cnt<<endl;
        //getch();
        if(k == 1){
            boardSwitch(i, j);  //switch on (i,j) position
            //cout<<i<<" "<<j<<" cnt = "<<cnt<<endl;
            //cnt++;
            //cout<<"switch on "<<i<<" "<<j<<" cnt = " <<cnt<<endl;
        }
        if(x == BOARDSIZE*BOARDSIZE-1){
//          if(isOn()){
//              minCount = minCount < cnt ? minCount : cnt;
//          }
        }
        else{
            turn(x+1);
        }
    }
    boardSwitch(i, j);  // return status before switch
    //cnt--;
}


int main(){
    for(int i = 0; i < BOARDSIZE; i++){
        for(int j = 0; j < BOARDSIZE; j++){
            board[i][j] = rand()%2;     }
    }
    boardDisp();
    turn(0);
    if(minCount == BOARDSIZE*BOARDSIZE){
        //There is no way to turn board on
        cout<<"There is no way to turn board on";
    }else{
        cout<<minCount;
    }
    return 0;
}

In my thought cnt is global variable and every function can change it's value. But there is no function change it's value but when i run that code (by code block, visual c++) sometime it print out value 1 for cnt variable and somtine 0. I see no operation can make change value of cnt but it's does change. why is that ?

在我看来,cnt是全局变量,每个函数都可以改变它的值。但是没有函数改变它的值,但是当我运行该代码时(通过代码块,visual c ++),有时它会为cnt变量和somtine 0打印出值1.我看到没有操作可以改变cnt的值,但它确实会改变。这是为什么 ?

1 个解决方案

#1


With the code commented as you have it, turn() keeps calling itself with increasing values of x until you get to turn(8).

随着代码的注释,turn()不断调整自身,增加x值,直到你转向(8)。

At that point, i gets set to '2' and j gets set to '2'. Then, you call boardSwitch(2,2).

此时,我被设置为'2'并且j被设置为'2'。然后,你调用boardSwitch(2,2)。

Your problem happens in boardSwitch(). Your for() loop keeps going until both i and j are equal to 3, ultimately resulting in a write to board[3][3]. This location doesn't exist, so you are just writing off the end of the variable -- at that point, anything could get clobbered. In your case, cnt is getting overwritten.

您的问题发生在boardSwitch()中。你的for()循环一直持续到i和j都等于3,最终导致写入板[3] [3]。这个位置不存在,所以你只是写下变量的结尾 - 在那一点上,任何东西都可能被破坏。在你的情况下,cnt被覆盖。

The main point is that there is nothing to prevent you from writing off the end of an array in c/c++. You just start writing to memory that isn't what you thought it was, and the program begins to behave unpredictably.

重点是没有什么可以阻止你在c / c ++中写出数组的结尾。你只是开始写入不像你想象的那样的内存,程序开始出现不可预测的行为。

Ultimately you need to fix your logic. One thing you might try in the meantime is creating a function to wrap writes to the array and perform bounds checking for you. For example:

最终你需要修复你的逻辑。在此期间您可能尝试的一件事是创建一个函数来包装对数组的写入并为您执行边界检查。例如:

    void writeToBoard(int i, int j, int value) {
        if (i >= BOARDSIZE) {
            printf("ERROR: Attempted to write outside array.\n");
            return;
        } else if(j >= BOARDSIZE) {
            printf("ERROR: Attempted to write outside array.\n");
            return;
        } else {
             board[i][j] = value;
        }             
    }

Then replace ALL writes to the array with calls to this function.

然后通过调用此函数替换对数组的所有写入。

This would catch the problem when it happens in an easier to debug way.

当它以更容易调试的方式发生时,这将捕获问题。

Wrapping the board in an object, making that object private, and exposing this sort of thing as a member function is an excellent example of encapsulation.

将板包装在一个对象中,使该对象成为私有,并将这种东西作为成员函数公开是封装的一个很好的例子。

An even better solution is to use standard library containers that do this thing for you (efficiently). That isn't always an option, and it's good to know conceptually how this sort of thing works. As a rule, though, there is very rarely a reason to implement your own bounds checked array. That's why we have the standard library.

更好的解决方案是使用标准库容器为您(高效)执行此操作。这并不总是一种选择,从概念上了解这种事情是如何运作的。但是,作为一项规则,很少有理由实现自己的边界检查数组。这就是我们拥有标准库的原因。

#1


With the code commented as you have it, turn() keeps calling itself with increasing values of x until you get to turn(8).

随着代码的注释,turn()不断调整自身,增加x值,直到你转向(8)。

At that point, i gets set to '2' and j gets set to '2'. Then, you call boardSwitch(2,2).

此时,我被设置为'2'并且j被设置为'2'。然后,你调用boardSwitch(2,2)。

Your problem happens in boardSwitch(). Your for() loop keeps going until both i and j are equal to 3, ultimately resulting in a write to board[3][3]. This location doesn't exist, so you are just writing off the end of the variable -- at that point, anything could get clobbered. In your case, cnt is getting overwritten.

您的问题发生在boardSwitch()中。你的for()循环一直持续到i和j都等于3,最终导致写入板[3] [3]。这个位置不存在,所以你只是写下变量的结尾 - 在那一点上,任何东西都可能被破坏。在你的情况下,cnt被覆盖。

The main point is that there is nothing to prevent you from writing off the end of an array in c/c++. You just start writing to memory that isn't what you thought it was, and the program begins to behave unpredictably.

重点是没有什么可以阻止你在c / c ++中写出数组的结尾。你只是开始写入不像你想象的那样的内存,程序开始出现不可预测的行为。

Ultimately you need to fix your logic. One thing you might try in the meantime is creating a function to wrap writes to the array and perform bounds checking for you. For example:

最终你需要修复你的逻辑。在此期间您可能尝试的一件事是创建一个函数来包装对数组的写入并为您执行边界检查。例如:

    void writeToBoard(int i, int j, int value) {
        if (i >= BOARDSIZE) {
            printf("ERROR: Attempted to write outside array.\n");
            return;
        } else if(j >= BOARDSIZE) {
            printf("ERROR: Attempted to write outside array.\n");
            return;
        } else {
             board[i][j] = value;
        }             
    }

Then replace ALL writes to the array with calls to this function.

然后通过调用此函数替换对数组的所有写入。

This would catch the problem when it happens in an easier to debug way.

当它以更容易调试的方式发生时,这将捕获问题。

Wrapping the board in an object, making that object private, and exposing this sort of thing as a member function is an excellent example of encapsulation.

将板包装在一个对象中,使该对象成为私有,并将这种东西作为成员函数公开是封装的一个很好的例子。

An even better solution is to use standard library containers that do this thing for you (efficiently). That isn't always an option, and it's good to know conceptually how this sort of thing works. As a rule, though, there is very rarely a reason to implement your own bounds checked array. That's why we have the standard library.

更好的解决方案是使用标准库容器为您(高效)执行此操作。这并不总是一种选择,从概念上了解这种事情是如何运作的。但是,作为一项规则,很少有理由实现自己的边界检查数组。这就是我们拥有标准库的原因。