来自标准输入的存储线永不变

时间:2019-06-02 02:45:36

标签: c algorithm

我正在研究这个问题(Uva227)。在测试案例时,我几乎收到了正确的结果,但是遇到了问题。我使用了函数gets()从标准输入中获取一行,并将其存储在a [0]中。但是在第一个输入矩阵之后,a [0]不再改变。怎么了?

P.S。在第2个谜题(即第二个输入矩阵)中,a [0]不变,所以我得到了错误的答案。但是,如果我把它放在第一位,它将返回正确的输出。因此,我认为该算法是正确的,但是在读取第一行时出了点问题。

英语不是我的母语;请原谅我的语法错误。

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

char a[5][5];



int main(){
    int _case = 1;
    char c;
    while(gets(a[0])){//Please focus on this line;it seems that a[0] never changed since first reading.
        if(a[0][0] == 'Z')  break;
        int blank_i, blank_j;
        for(int i = 0; i < 5; i++){
            if(i)   gets(a[i]);
            for(int j = 0; j < 5; j++){
                if(a[i][j] == ' '){
                     blank_i = i;
                     blank_j = j;
                }
            }
        }
        bool flag = true;
        int i = 0;
        while((c = getchar()) != '0'){
            switch(c){
                case 'A':
                    a[blank_i][blank_j] = a[blank_i - 1][blank_j];
                    a[--blank_i][blank_j] = ' ';    break;
                case 'B':
                    a[blank_i][blank_j] = a[blank_i + 1][blank_j];
                    a[++blank_i][blank_j] = ' ';    break;
                case 'L':
                    a[blank_i][blank_j] = a[blank_i][blank_j - 1];
                    a[blank_i][--blank_j] = ' ';    break;
                case 'R':
                    a[blank_i][blank_j] = a[blank_i][blank_j + 1];
                    a[blank_i][++blank_j] = ' ';    break;
                default:    break;
             }
        }
        //add a getchar() here will fix the problem.
        printf("Puzzle #%d:\n", _case);
        if(blank_i < 0 || blank_i > 4 || blank_j < 0 || blank_j >  4)
             printf("This puzzle has no final configuration.\n");
        else{
            for(int i = 0; i < 5; i++){
                for(int j = 0; j < 5; j++){
                    printf("%c ", a[i][j]);
                }
            printf("\n");
            }
        }
        printf("\n");
        _case++;
    }
    return 0;
}

2 个答案:

答案 0 :(得分:1)

您误诊了问题。并不是“在第一个输入矩阵之后,a [0]不再改变”。实际的问题是,在您阅读了结束移动列表的'0'之后,在下一个难题开始之前会有换行符。您的代码没有考虑到这一点,因此将换行符视为下一个难题的第一行的第一个字符。在返回while循环的开头之前,请先吞下此换行符来解决此问题。

此外:一些评论者指出,您不应使用gets。他们是100%正确的,但这与这个问题无关,并且放弃它不会解决此问题。

答案 1 :(得分:0)

除了Joeseph的答案外,您还由于无法验证您的i, j, blank_i, blank_j索引是否仍在范围内而邀请了未定义行为。 (并且*永远不要使用gets(),它已从当前的C标准中删除)。参见:Why gets() is so dangerous it should never be used!

相反,使用fgets并通过 nul-characer (例如

)覆盖,从结果字符串中修剪尾随'\n'
#define ROWS 5      /* if you need a constant, #define one (or more) */
#define COLS ROWS

char a[ROWS][COLS];
...
        for(int i = 0; i < ROWS; i++){
            if (i)                                  /* skips a[0] */
                if (fgets (a[i], COLS, stdin))
                    a[i][strcspn(a[i], "\n")] = 0;  /* overwrite '\n' */
                else {  /* handle failed input */
                    fputs ("error: EOF encountered.\n", stderr);
                    return 1;
                }
           ...

接下来,在下面的for循环中,您分配blank_i = i;blank_j = j;,例如

            for (int j = 0; j < COLS; j++){
                if(a[i][j] == ' ') {
                     blank_i = i;
                     blank_j = j;
                }
            }

随后,您随后递增a[blank_i++][blank_j];并使用blank_j--blank_j++(还必须确保blank_i--永远不会产生负值)。为了避免未定义行为,您必须验证索引是否在范围内。例如,使用您的case 'B':,您可以执行以下操作:

                case 'B':
                    {   /* create new block to allow variable declaration
                         * blank_i + 1 can exceed 4 invokding Undefined
                         * Behavior. You must validate/handle value.
                         */
                        int row = blank_i + 1 % ROWS;
                        a[blank_i][blank_j] = a[row][blank_j];
                        /* same with ++blank_i */
                        blank_i = (blank_i + 1) % ROWS;
                        a[blank_i][blank_j] = ' ';
                        break;  /* lines don't cost $, done hide break at end */
                    }

由于您正在循环while ((c = getchar()) != '0'),因此值blank_iblank_j都可能超出数组范围,或者导致负索引调用 Undefined Behavior -很久以前您曾经的支票:

        printf("Puzzle #%d:\n", _case);
        if(blank_i < 0 || blank_i > 4 || blank_j < 0 || blank_j >  4)
             printf("This puzzle has no final configuration.\n");

仔细检查并修改索引(以任何需要的方式处理),以验证索引是否在数组的范围内。