我正在研究这个问题(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;
}
答案 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_i
和blank_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");
仔细检查并修改索引(以任何需要的方式处理),以验证索引是否在数组的范围内。