| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 749 人关注过本帖
标题:奇怪,怎么会出现缓冲区溢出呢?
只看楼主 加入收藏
神龙赖了
Rank: 10Rank: 10Rank: 10
来 自:萨塔星
等 级:青峰侠
威 望:2
帖 子:711
专家分:1788
注 册:2012-10-13
结帖率:97.22%
收藏
已结贴  问题点数:30 回复次数:15 
奇怪,怎么会出现缓冲区溢出呢?
程序代码:
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#define SIZE 6
const char black_d='@';  //电脑用的棋子
const char white_p='O';  //玩家用的棋子

void qi_pan(char board[][SIZE]);  //显示棋盘
void shuo_ming(void);  //说明规则
int valid_moves(char board[][SIZE],bool moves[][SIZE],char player);  /*确定有效步骤*/
void make_move(char board[][SIZE],int row,int col,char player);  //完成落子后的“兵变”
void computer_move(char board[][SIZE],bool moves[][SIZE],char player);  //电脑移动
int get_score(char board[][SIZE],char player);  //辅助函数,得到我方棋子数
int best_move(char board[][SIZE],bool moves[][SIZE],char player);  //辅助函数,得到最佳分数

int main(void)
{
    char board [SIZE][SIZE]={0};
    bool moves [SIZE][SIZE]={0};
    char answer[12];
    int row=0;
    int col=0;
    int mid=0;
    int no_of_moves=0;               /*记录棋子number*/
    int no_of_game=0;                /*记录游戏count*/
    int invalid_moves=0;             /*无效次数*/
    int comp_score=0;                /*电脑棋子数*/
    int user_score=0;                /*用户棋子数*/
    bool next_player=true;           /*true为电脑下,flase为user下*/
    int x = 0;                       /*记录user输入的行数*/
    char y = 0;                      /*记录user输入的列数*/

    printf("\n翻转棋戏\n\n");
    printf("你能在这里和电脑对弈\n");
    printf("你将使用白棋,电脑使用黑棋\n");
    printf("如不明白游戏规则请输入help,那里将会对游戏规则进行详细讲解\n");
    printf("否则输入go开始游戏(也可以输入out直接退出):");
    fgets(answer,sizeof(answer),stdin);
    if(tolower(answer[0])=='h')
    shuo_ming();  //检测是否需要解释

    /*start the game*/
    while((tolower(answer[0])=='g' && tolower(answer[1])=='o') || tolower(answer[0])=='h')
    {
        next_player= !next_player;
        no_of_moves=4;  /*记录开盘棋子数*/

        //设棋盘每处为空格
    for(row=0;row<SIZE;row++)
        for(col=0;col<SIZE;col++)
            board[row][col]=' ';

    mid=SIZE/2;  //开始使首先摆放四颗棋子,故居中
    board[mid-1][mid-1]=board[mid][mid]='@';  //放黑棋
    board[mid-1][mid]=board[mid][mid-1]='O';  //放白棋

    /*与玩家对弈*/
    do
    {
        qi_pan(board);

        //如果是用户下...
        if(next_player = !next_player)
        {
            if(valid_moves(board,moves,white_p))  //还有有效步骤
            {
                //循环直到正确输入
                for(;;)
                {
                    printf("请输入你想要下的地方(行 列):");
                    scanf(" %d %c",&x,&y);
                    getchar();
                    y=tolower(y)-'a';  //转换为列索引
                    x--;  //转换为行索引
                    if(x>=0 && x<SIZE && y>=0 && y<SIZE && moves[x][y])
                    {
                        make_move(board,row,col,'O');
                        no_of_moves++;
                        break;
                    }
                    else
                        printf("你输入的为无效棋子,请重新输入\n");
                }
            }

            //当没有有效步骤时...
            else
            if(++invalid_moves<2)
                printf("你以没有有效步骤,所以你必须跳过\n");
            else
                printf("我们都没有可动的地方了,所以棋局结束:");
        }
        else
        {
            //电脑'true
            if(valid_moves(board,moves,'@'))
            {
                computer_move(board,moves,'@');
                no_of_moves++;
                break;
            }
            else
            if(++invalid_moves<2)
                printf("我没有可动的地方,所以我必须跳过,请你继续输入");
            else
                printf("我们都没有可动的地方了,所以棋局结束:");
        }
    }while(no_of_moves<SIZE*SIZE && invalid_moves<2); 

        /*处理结果*/
        qi_pan(board);  //显示最后结果的棋盘
        comp_score=user_score=0;  

        //浏览全盘
        for(row=0;row<SIZE;row++)
            for(col=0;col<SIZE;col++)
            {
                user_score += board[row][col] == white_p;
                comp_score += board[row][col] == black_d;
            }

            printf("\n结果为:\n");
            printf("白棋%2d  \n黑棋%2d\n\n",user_score,comp_score);
            printf("你还想继续下去吗?(go/out):");
            fgets(answer,sizeof(answer),stdin);
            printf("%s\n",answer);
    }
    return 0;
}

因为程序有点大,所以只把main函数放出来了,
考虑到程序有点大,如果嫌麻烦的话不用太看上面的代码
我想问的是:
程序代码:
int main(void)
{
    char a,b,c;
    scanf("%c",&a);
    printf("a==%c\n",a);
    scanf(" %c",&b);
    printf("b==%c\n",b);
    scanf("%c",&c);
    printf("%c\n",c);
    return 0;
}

中scanf()会遗留下‘\n',而( %d)只能跳过却不能删除
可是:
程序代码:
#include <stdio.h>

int main(void)
{
    char a,b,c;
    scanf("%c",&a);
    printf("a==%c\n",a);
    scanf(" %c",&b);
    printf("b==%c\n",b);
    return 0;
}
虽然在缓冲区遗留了一个'\n'却也不是溢出
那缓冲区溢出到底是什么意思啊?

希望能讲清楚点,谢谢

 
搜索更多相关主题的帖子: 缓冲区 
2012-11-18 10:29
pauljames
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:千里冰封
威 望:9
帖 子:1555
专家分:10000
注 册:2011-5-8
收藏
得分:2 
你用个getchar()把那个'\n'吸收掉就好了

经常不在线不能及时回复短消息,如有c/单片机/运动控制/数据采集等方面的项目难题可加qq1921826084。
2012-11-18 15:44
神龙赖了
Rank: 10Rank: 10Rank: 10
来 自:萨塔星
等 级:青峰侠
威 望:2
帖 子:711
专家分:1788
注 册:2012-10-13
收藏
得分:0 
我知道getchar()和fflush(stdin)可以清空缓冲区,但用在这里不对
问题主要出在那几个函数中,现在我已经改过来了,好吧,楼上打酱油的,还是谢谢你了...

我有个关于scanf()的问题
  
程序代码:
#include <stdio.h>

int main(void)
{
    char a=0,b=0;
    scanf("%c",&a);
    printf("a==%d\n",a);
    scanf("%c",&b);
    printf("b==%d\n",b);
    return 0;
}

连续输入两个回车会得到'\n'的ASCLL值10;
而如果在scanf("%c",&b);的后面加上getchar()
的话在遇到关于b的输入的时候需要连续打两下空格
也许这也关系到缓冲区,但是我实在弄不懂其中的运行
希望能一步一步详细写出内部运行,当然如果能使我弄懂自然照样给分啦,非常感谢!

I have not failed completely
2012-11-18 20:58
神龙赖了
Rank: 10Rank: 10Rank: 10
来 自:萨塔星
等 级:青峰侠
威 望:2
帖 子:711
专家分:1788
注 册:2012-10-13
收藏
得分:0 
后面加上getchar()
的话在遇到关于b的输入的时候需要连续打两下空格

是连续打两下回车,笔误笔误...

I have not failed completely
2012-11-18 21:00
youngdavid
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:107
专家分:698
注 册:2012-9-24
收藏
得分:0 
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢出的数据覆盖在合法数据上,理想的情况是 程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间想匹配,这就为缓冲区溢出埋下隐患.操作系统所使用的缓冲区 又被称为"堆栈". 在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出 .//百度
2012-11-18 21:01
youngdavid
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:107
专家分:698
注 册:2012-9-24
收藏
得分:27 
“连续输入两个回车会得到'\n'的ASCLL值10;”   是因为scanf("%c",&a);的时候scanf 对%c处理的时候,不会跳过回车,它将你输入的第一个回车接受,并赋值给a,在下一句printf("a==%d\n",a);将a作为整数打印的时候,就打印出回车的ASCLL值也就是10. 你接着再输入第二个回车,在下一个scanf("%c",&b);语句赋值给b,然后接下来同样打印出10.
因为scanf("%c",&a);语句会把缓冲区读入的第一个字节赋值给a,所以你输入一个M再按回车,M赋值给了a,回车就存在缓冲区,这时候你就需要用语句清空回车。你的代码可以这么改:
#include <stdio.h>
int main(void)
{
    char a=0,b=0;
    scanf("%c",&a);
    while(getchar()!='\n')
    continue;
    printf("a==%d\n",a);
    scanf("%c",&b);
    while(getchar()!='\n')
    continue;
    printf("b==%d\n",b);
    return 0;
}

2012-11-18 21:23
青春无限
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江苏
等 级:贵宾
威 望:24
帖 子:3452
专家分:19340
注 册:2012-3-31
收藏
得分:1 
看看

学 会看代码…学习写程序…学会搞开发…我的目标!呵呵是不是说大话啊!!一切皆可能
2012-11-18 21:28
神龙赖了
Rank: 10Rank: 10Rank: 10
来 自:萨塔星
等 级:青峰侠
威 望:2
帖 子:711
专家分:1788
注 册:2012-10-13
收藏
得分:0 
回复 6楼 youngdavid
我基本懂了,但是getchar()如果那么用的话就是查看缓冲区内的信息,getchar()又可以用来清除,搞得我有点混乱...能不能讲一下这一步
while(getchar()!='\n')
    continue;

分还是先结了吧,免得人家说我不厚道...

I have not failed completely
2012-11-18 21:55
一个孩子
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:5
帖 子:356
专家分:954
注 册:2012-10-1
收藏
得分:0 
回车符是一个很奇妙的字符,因为在每一个程序的输入结束时几乎都要用到它,它一般是用来结束输入的。而你的问题我感觉应该这样理解:
1.关于b的输入,你在scnaf("%c",&b);后加了getchar();假设你想打印回车符的ASII码的值,你可以这样理解:你第一次敲的回车符,把它当做一个普通的字符,而你第二次敲的回车符的作用就又回到它原来的功能了,提示结束输入。并用getchar();来吸收你的第二个回车符。打印的是你第一次敲的回车符的ASII码值;
2:其实,getchar();你也可以放到scanf("%c",&b);之前,理解方法是一样的。缓冲区什么的最讨厌了

重要的不是结果,是求一个结果的过程,哪怕千难万难,当你有想要的结果时,你已走的很远
2012-11-18 22:07
神龙赖了
Rank: 10Rank: 10Rank: 10
来 自:萨塔星
等 级:青峰侠
威 望:2
帖 子:711
专家分:1788
注 册:2012-10-13
收藏
得分:0 
哎,真是云里雾里 雾里云里,似懂非懂啊...还是先不想了吧..。

I have not failed completely
2012-11-18 22:18
快速回复:奇怪,怎么会出现缓冲区溢出呢?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020529 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved