Blog·Tanky WooABOUTRSS

scanf输入字符的总结--百练2816红与黑

19 May 2010
这篇博客是从旧博客 WordPress 迁移过来,内容可能存在转换异常。

今天,在做百练OJ 2816时遇到了问题。 主要不是算法,而是细节,也让我知道了对基础的严格掌握是多么重要,而今天要说的就是scanf("%c",...)这个细节。 看程序:百练OJ 2816红与黑 我的代码(WA的): //ID:百练OJ 2816红与黑 //网站:C++奋斗乐园|C++论坛|算法论坛|ACM/ICPC论坛 //地址:http://www.cppleyuan.com/ //个人主页:www.wutianqi.com //豆瓣小组:http://www.douban.com/group/cppleyuan/ //转载请写上本帖链接及站点名称:”Tanky Woo与ACM一起做过的日子“和“C++奋斗乐园|C++论坛|算法论坛|ACM/ICPC论坛”

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define MAX_NUM 21
int W, H;
char aTile[MAX_NUM][MAX_NUM];

int dp(int i, int j);

int cnt = 0;
int main()
{
    while(scanf("%d %d", &W, &H) == 2 && W != 0 && H 

!= 0)
    {
        memset(aTile, 0, sizeof(aTile));
        for(i = 0; i < H; i++)
        {
            for(j = 0; j < W; j++)
            {
                scanf("%c", &aTile[i][j]);  

                if(aTile[i][j] == '@')
                {
                    pos_i = i;
                    pos_j = j;
                }

            }
        }

        printf("%d\n", dp(pos_i, pos_j));
    }
    return 0;
}

int dp(int i, int j)
{
    if(i<0 || i>=H || j<0 || j>=W)
        return 0;
    if(aTile[i][j] == '#')
        return 0;
    else
    {
        aTile[i][j] = '#';
        return 1 + dp(i+1, j) + dp(i-1, j) + dp(i, 

j+1) + dp(i, j-1);
    }

大家可以测试下: 输入: 6 9 ....#. .....# ...... ...... ...... ...... ......

@...

.#..#. 0 0 而输出却不是上面的图案。 这是为什么呢?原来: scanf("%c",...)对于空格和回车键都可以接受(回车键包含回车

和换行2个ASCII码,分别是10和13,但是用scanf("%c")输入时再

输出则是10,这是因为%c只接受一个字符的原因),所以,解决方

法就是加一个getchar(), 代码局部如下:

        for(i = 0; i < H; i++)
        {
            for(j = 0; j < W; j++)
            {
                scanf("%c", &aTile;[i][j]); 


                if(aTile[i][j] == '@')
                {
                    pos_i = i;
                    pos_j = j;
                }

            }
            getchar();  //消除每输入6个字符的

换行的回车键

        } 

但是会发现问题还是没有解决,这是为什么呢? 再观察,原来在while(scanf())中的回车键也没消除掉。 所以局部改为:

    while(scanf("%d %d", &W;, &H;) == 2 && W != 0 && H 

!= 0)
    {
        memset(aTile, 0, sizeof(aTile));
        int i, j;
        int pos_i, pos_j;  // 为"@"的坐标
        getchar();         //消除while中scanf的回

车键
        for(i = 0; i < H; i++)
        {
            for(j = 0; j < W; j++)
            {

这下应该是对的了吧。 用freopen充定向去测试,把网页上题目给出的数据粘贴到txt中,

测试。。。还是乱,答案错误。 但是,用手动的去测试却发现,居然是对的。这下郁闷了,以为是

在CMD和TXT中的回车键的ASCII不一样,但是 测试都输出10。 终于,发现了是哪错误,原来在TXT中没一行数据末都多出以一个

空格!这就是元凶!记得在以前一道百练的题目 也是手动就是对的,但是freopen就错误了,先开始还以为是

freopen不能这么用,现在看来,十有八九是 同样的原因,下次在把数据从网页粘贴到TXT中要注意了,因为以

前可能对于%d没感觉。但是对于%c就不好说了, 所以在使用scanf("%c")是要格外注意空格和换行。

正题的代码如下(已AC):

 #include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define MAX_NUM 21
int W, H;
char aTile[MAX_NUM][MAX_NUM];

int dp(int i, int j);

int cnt = 0;
int main()
{   
    //freopen("input_2816.txt", "r", stdin);
    while(scanf("%d %d", &W;, &H;) == 2 && W != 0 && H 

!= 0)
    {
        memset(aTile, 0, sizeof(aTile));
        int i, j;
        int pos_i, pos_j;  // 为"@"的坐标
        getchar();
        for(i = 0; i < H; i++)
        {
            for(j = 0; j < W; j++)
            {
                scanf("%c", &aTile;[i][j]); 


                if(aTile[i][j] == '@')
                {
                    pos_i = i;
                    pos_j = j;
                }

            }
            getchar();  //消除没输入6个的换行

的回车键

        }           
        printf("%d\n", dp(pos_i, pos_j));
    }
    return 0;
}

int dp(int i, int j)
{
    if(i<0 || i>=H || j<0 || j>=W)
        return 0;
    if(aTile[i][j] == '#')
        return 0;
    else
    {
        aTile[i][j] = '#';
        return 1 + dp(i+1, j) + dp(i-1, j) + dp(i, 

j+1) + dp(i, j-1);
    }
} 

但是,针对有回车和空格的字符输入来说,gets()是一个好的选择

: (gets()版的解法):

 #include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define MAX_NUM 21
int W, H;
char aTile[MAX_NUM][MAX_NUM];

int dp(int i, int j);

int cnt = 0;
int main()
{
    int i, j;
    //freopen("input_2816.txt", "r", stdin);
    while(scanf("%d %d", &W;, &H;) == 2 && W != 0 && H 

!= 0)
    {
        for(i = 0; i < H; i++)
            scanf("%s", aTile[i]);
        for(i = 0; i < H; i++)
            for(j = 0; j < W; j++)
                if(aTile[i][j] == '@')
                    printf("%d\n", dp

(i, j));
    }
    return 0;
}

int dp(int i, int j)
{
    if(i<0 || i>=H || j<0 || j>=W)
        return 0;
    if(aTile[i][j] == '#')
        return 0;
    else
    {
        aTile[i][j] = '#';
        return 1 + dp(i+1, j) + dp(i-1, j) + dp(i, 

j+1) + dp(i, j-1);
    }
}