【问题标题】:Encountering an infinite loop depending on compiler and declarations根据编译器和声明遇到无限循环
【发布时间】:2012-07-23 23:41:28
【问题描述】:

在这个程序中有一行我创建了一个名为 “疯狂整数”。

如果我不创建这个变量,MinGW 会创建一个无限循环! 其他编译器似乎没有这个问题。

谁能告诉我这里发生了什么?

重新创建:使用 MingW 下载最新版本的 CodeBlocks,创建 一个新的控制台项目,然后尝试运行这个程序。

然后,尝试删除我创建“crazy_integer”的代码行 并再次运行该程序。结果应该是一个无限循环。

// In this program there is a line where I create a variable called 
// "crazy_integer". 
//
// If I do not create this variable, CodeBlocks creates an infinite loop!
// I do not seem to have this problem with any other compiler.
//
// Can anyone tell me what is going on here? 
//
// To recreate: Download the latest version of CodeBlocks with MingW, create
// a new console project, and try running this program.
//
// Then, try removing the line of code where I create "crazy_integer" 
// and run the program again. The result should be an infinite loop.

#include <stdio.h>
#include <string.h>

int find_winning_move(char *, char, int);
int display_board(char *);
int is_winning_position(char *, char);
void show_win_details(int, char);

int main(void) {
    int retval = 0;
    char raw_data[]         = "X  X XO  ";
    char player = 'X';

    printf("We are examining this board:  \n");
    display_board(raw_data);

    find_winning_move(raw_data, player, 1);

    return 0;
}

int find_winning_move(char *raw_data, char player, int depth) {

    char test_position[9];
    int crazy_integer=0;    // Adding this line will fix an infinite loop
    int i, win_result;

    for (i = 0; i < 9; i++) {
        if (raw_data[i] == ' ') {
            strcpy(test_position, raw_data);
            test_position[i] = player;
            win_result = is_winning_position(test_position, player);
            printf("The result of playing %c at position %d is: %d  \n",
                player, i, win_result);

            display_board(test_position);
        }
    }

    return 0;
}

int display_board(char *raw_data) {
    char display_model[]     = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";

    int i, j, k; k=0;

    for (i = 0; i <= 2; i++) {
        for (j = 1; j <= 7; j+=3) {
            display_model[ (i * 10) + j ] = raw_data[k++];
        }
    }

    printf("%s ", display_model);
}

int is_winning_position(char *raw_data, char player) {

    int i;

    // Test for horizontal win
    for (i = 0; i <= 6; i+=3) {
        if (raw_data[i] == player
            && raw_data[i+1] == player
            && raw_data[i+2] == player)
        {
            return 10 + i;
        }
    }

    // Test for vertical win
    for (i = 0; i <= 2; i++) {
        if (raw_data[i] == player
            && raw_data[i+3] == player
            && raw_data[i+6] == player)
        {
             return 20 + i;
        }
    }

    // Test for diagonal win
    if (raw_data[4] == player) {
        if (raw_data[0] == player && raw_data[8] == player) {
            return 31;
        }
        if (raw_data[2] == player && raw_data[6] == player) {
            return 32;
        }
    }

    return 0;

}

void show_win_details(int win_value, char player) {

    switch (win_value) {

        // Horizontal
        case 10 :
            printf("Horizontal win on first row for Player: %c  \n",
                player);
        break;
        case 13 :
            printf("Horizontal win on second row for Player: %c  \n",
                player);
        break;
        case 16 :
            printf("Horizontal win on third row for Player: %c  \n",
                player);
        break;

        // Vertical
        case 20 :
            printf("Vertical win on first column for Player: %c  \n",
                player);
        break;
        case 21 :
            printf("Vertical win on second column for Player: %c  \n",
                player);
        break;
        case 22 :
            printf("Vertical win on third column for Player: %c  \n",
                player);
        break;

        // Diagonal
        case 31 :
            printf("Diagonal win upper left to lower right for Player: %c  \n",
                player);
        break;
        case 32 :
            printf("Diagonal win lower left to upper right for Player: %c  \n",
                player);
        break;

        default: printf("Some error occurred.  \n"); break;

    }
}

【问题讨论】:

    标签: c windows mingw


    【解决方案1】:

    你的变量声明:

    char test_position[9];
    

    对于 strcpy 来说太短了 (strcpy(test_position, raw_data);)。源缓冲区raw_data 是 9 个字符加上空终止符。所以它会导致缓冲区溢出。添加该整数变量可能会在堆栈上提供额外的空间来“修复”堆栈溢出。

    【讨论】:

    • 我怀疑将test_position的声明移动两个ints的声明之后也将解决无限循环。您仍然会破坏堆栈,但至少不会破坏循环计数器。
    • 是的,当然,这很有意义。那么问题来了,为什么它可以在其他编译器中工作?当我写它时它在 Linux 中运行良好:gcc test.c -o test
    • @user1547160 不同的编译器可以按不同的顺序排列堆栈变量,或者可以在它们之间使用不同数量的填充。正如所写的那样,您的代码肯定不会在 Linux 中“工作”。您根本还没有看到灾难性的失败(“尚未”是有效的词)。堆栈仍然被破坏,所以危险仍然存在。
    • @user1547160:堆栈布局取决于编译器。缓冲区溢出会导致未定义的行为。正如有人在一个答案中提到的那样,当触发未定义的行为时,您的计算机为您订购披萨是完全合法的(它甚至可能要求凤尾鱼)。
    猜你喜欢
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    相关资源
    最近更新 更多