C语言作业——弟弟的作业、中文字符对函数的碰撞

每两日一书写,快来跟我一块加油吧!以下大多是个人的想法以及评论,本人的学术水平不足,如出现什么纰漏以及不足望大家指正,帮助学者进步,谢谢大家。下文如果对大家有益,学者心中会感到莫大的欢喜!

你的弟弟刚做完了“100以内数的加减法”这部分的作业,请你帮他检查一下。每道题目(包括弟弟的答案)的格式为a+b=c或者a-b=c,其中a和b是作业中给出的,均为不超过100的非负整数;c是弟弟算出的答案,可能是不超过200的非负整数,也可能是单个字符"?",表示他不会算。

输入格式

输入文件包含不超过100行,以文件结束符结尾。每行包含一道题目,格式保证符合上述规定,且不包含任何空白字符。输入的所有整数均不含前导0。

输出格式

输出仅一行,包含一个非负整数,即弟弟答对的题目数量。

样例输入

1+2=3
3-1=5
6+7=?
99-0=99

样例输出

2

最近作者缺少时间在从头开始独自思考,便采用了他人的优秀作品进行借鉴。

思路:输入数据并用合适的方法储存后,能够进行判断。还要注意以文件结束符结尾。

#include<stdio.h>
main()
{
    char op;
    int a,b,c,k,score=0;
    while(~(k=scanf("%d%c%d=%d",&a,&op,&b,&c))){
        if(k==3) getchar();//读取缓存区回车 
        else if(op=='+' && c==a+b) score++;
        else if(c==a-b) score++;
    }
    printf("%d",score);
 }

作者: mirage   发表时间:2018-08-05 15:55:19 来源 dotcpp.com网站

这个思路相对简洁且容易理解,堪当典范,但也存在部分缺陷,现在我们来分析一下这个作品。

从while内的条件内先出现了“~”字符,是按位取反符(反码运算符),对于二进制进行取反,并变成补码的形式1→0000 0001,它的取反为1111 1110 ,这个二进制数表示的是-2(文末详细介绍)

按位取反符号内是‘k=scanf(4个参数)’,scanf函数读入成功时,可以返还读入成功的参数的数量(一定是读入成功的)。不成功即返回0(相当于一个也没读入成功)。且当输入文件结束符(∧z),会读入NULL(对应值为-1)。当输入文件结束符时,‘k=-1’,对‘-1’进行按位取反,得到的是0,条件为0,跳出循环。

scanf()里的4个参数对应要读入的数据。

第一个‘if’,负责判断是否输入了‘1+2=?’这种情况。

第二、三个‘if’,负责检查运算符为正和负时,进行加减判断,并且在正确时进行记录。

突破性思维:没有按照正常思维去理解运算式,而巧妙地运用了scanf函数读入数据的特点(%d只能读入整数,遇见其他结束%d的读入;%c只能读入一个字符;),还运用了scanf函数返回的值。这种思维值得去思考。

不足与反思:

1.在scanf函数读入数据时,对于“1+2=?”这种情形时,如果输入的是中文“?”,系统就会进入死循环,不需要再输入任何数据,一直反复循环。进行探究发现,中文的字符所占的字节至少为2个,scanf函数先发现“?”,读取了一半,然后当getchar函数在读取字符时,也只能读入一个字节(英文字符),导致了缓冲区仍然存在数据(回车),导致了造成了清空缓冲区失败,当再遇见scanf函数时,就会读入回车,那直接跳出scanf函数继续往下,一直重复,进入了死循环中。如果添加了

for(int i=0;i<2;i++)getchar();//只能清空中文字符为2个字节时具有局限性
while ((c = getchar()) != '\n' && c != EOF); //能清空所有缓冲区的内容

 

即使输入的是中文“?”也可以循环。,因为一次至少拿走了两个数据。

2.还没有对题设条件中,超过100个数据时,不能再读入,以及所回答的答案不是小于-200的数

作品二:

#include <stdio.h>
 
int M = 0, i = 0, x = 0, y = 0, z = 0;
 
 
void transfer( char *s );
 
 
int main()
{
    char    c;
    char    a[1000];
 
    while ( (c = getchar() ) != EOF )
    {
        a[i] = c;
        i++;
    }
    a[i] = '\0';
 
    transfer( a );
 
    printf( "%d", M );
 
    return(0);
}
 
 
void transfer( char *s )
{
    x    = 0;
    y    = 0;
    z    = 0;
 
 
    int jiaorjian = 4;                  /* 用于记录运算符 */
    if ( (*s) == '\0' || (*s) == '\n' )
        return;
 
    while ( (*s) != '+' && (*s) != '-' )
    {
        x = x * 10 + (*s) - '0';
        s++;
    }
 
    if ( (*s) == '+' )
    {
        jiaorjian = 1;
    }                                /* +等于1 */
    else
    if ( (*s) == '-' )
    {
        jiaorjian = 0;
    }
 
    s++;
    while ( (*s) != '=' )
    {
        y = y * 10 + (*s) - '0';
        s++;
    }
 
    s++;
 
    while ( (*s) != '\n' )
    {
        if ( (*s) == '?' )
        {
            z = -1;
            s++;
        }else  { z = z * 10 + (*s) - '0';
             s++; }
    }
 
    s++;            /* 这里回车占两个字符所以还要++ */
 
 
    if ( z != -1 )  /* z==-1表示不会做 */
    {
        if ( jiaorjian == 1 )
        {
            if ( x + y == z )
                M++;
        }
        if ( jiaorjian == 0 )
        {
            if ( x - y == z )
                M++;
        }
    }
 
 
    transfer( s++ ); /* 递归处理 */
 
    return;
}

作者: Manchester     发表时间:2017-12-13 00:10:51  来自dotcpp.com

这是比较常规的想法,但是内容比较多,容易记忆紊乱,需细心地写。其中回车是占一个字符,不过字符串末尾是以\0结尾的因此应多加一,来跳过结尾字符,这种思路更为关键,更考察基本功。本人不再过多解读。

附录一

反码的补码:对于 1111 1110 这个反码,先进行取反,得0000 0001再+1,得0000 0010为2,最后加个“-”,即“-2”。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值