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