问题描述
这是去年我大学的第一次“编程入门”考试中的一个问题:
使用
getchar()
函数读取包含以下内容的输入序列: 数字,+和-号。输出应该是那些的结果 算术运算。
例如,如果输入为10+13-12+25-5+100
,则输出应为131
。
现在,考虑到我在参加uni之前有一点C的经验,使用指针,数组等似乎很容易解决这个问题。
但这是要注意的地方:在考试中,您只能使用到目前为止学生所教过的内容。并且鉴于此考试就像学年开始后一个月一样,您的选项是相当有限的。
您只能使用变量,基本输入/输出内容,运算符(逻辑和按位),条件语句和循环,函数。
这意味着没有:数组,字符串,指针,递归,结构,或者基本上是其他任何可以简化此过程的东西。
该怎么办?今天是我第二次花3个小时来解决这个问题。我已经成功解决了它,但是只有在“作弊”并使用数组,字符串函数(strtol
)和指针之后才能解决。对我来说,重要的是要知道如何按照规则解决问题,因为我即将参加的考试也有类似的内容。
编辑:到目前为止,我的尝试总计是将while循环与getchar()
组合在一起进行输入,之后我被卡住了。如果不使用更多的“工具”,我对应该怎么做一无所知。
解决方法
解决方案非常简单,但对于初学者而言可能并不明显。我不会提供完整的程序,而是概述了仅需几个变量即可实现该程序的步骤。
首先,请注意以下两点很重要:
- 您的输入只能包含
-
,+
或任何数字(0123456789
)之一。 -
getchar()
函数一次将读取一个字符,并在到达输入末尾或发生错误时返回EOF
。
现在,进入解决方案:
-
从循环中一次读取一个字符开始。您只有在达到输入结尾或发生错误时才会停止:
int c; while ((c = getchar()) != EOF) { // logic here }
-
从将累加器设置为
0
开始,并在每次遇到数字时向其“添加”数字。// outside the loop int acc = 0; // inside the loop if (/* c is a digit */) acc = acc * 10 + (c = '0');
提示:
/* c is a digit */
条件可能并不简单,您可以将其放在检查else
和-
的{{1}}中。 -
每次遇到
+
或-
时,请记住该操作,并且每次遇到操作员时,请首先执行上一个操作并重置累加器。+
-
到达输入的末尾(即退出循环)时,请执行最后一个操作(与
// outside the loop int op = 0; int result = 0; // inside the loop if (c == '+' || c == '-') { if (op) { // there already is a previous operation to complete,do it if (op == '+') result += acc; else result -= acc; } else { // first operation encountered,don't do anything yet result = acc; } acc = 0; // reset op = c; // remember the current operation for the future }
中的点3相同的逻辑)。 -
输出结果:
您通常会写类似:
if
但是,如果不能使用字符串文字(
printf("%d\n",result);
)或"%d\n"
函数,则必须使用printf()
手动进行。这基本上与我们之前将数字扫描到累加器中相反。-
如果需要,请先打印符号,然后将值设置为正值:
putchar()
-
找到小于您的数字的最大乘方10:
if (result < 0) { putchar('-'); result = -result; }
-
使用幂除法并以10为模对每个数字进行提取和打印:
int div = 1; while (result / div / 10) div *= 10;
注意:开头的
while (div) { putchar('0' + ((result / div) % 10)); div /= 10; }
用于将数字(从0到10)转换为相对的ASCII字符。 -
以换行符结尾:
'0' +
-
编写解析器时,通常会发现自己“缓冲”了“将要完成的下一个操作”。当输入更改状态时-您正在读取数字,但随后读取了一个操作-然后执行“缓冲”操作并缓冲将来将要执行的下一个操作。
示例:
10+13-12
^^ - we read 10
^ - result=10 - we buffer that we *will* have to do + in the future
^^ - reading 13
^ - och we stopped reading numbers!
we execute _buffered_ operation `+`,so we do result += 13
and buffer `-` to be done in the future
^^ - we read 12
^ - och,EOF! we execute buffered operation `-`,so we do result -= 12
- etc.
代码:
#include <stdio.h>
int main() {
int result = 0; // represents current result
int temp = 0; // the temporary number that we read into
int op = 0; // represents the _next_ operation that _will_ be done
while (1) {
int c = getchar();
switch (c) {
// we read an operation,so we should calculate _the previous_ operation
// or this is end of our string
case '+': case '-': case EOF:
if (op == 0) {
// we have nothing so far,so start with first number
result = temp;
} else if (op == '+') {
result += temp;
} else if (op == '-') {
result -= temp;
}
// the next operation we will do in future is stored in op
op = c;
// current number starts from 0
temp = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// read a digit - increment temporary number
temp *= 10;
temp += c - '0';
break;
}
// we quit here,the result for last operation is calculated above
if (c == EOF) {
break;
}
}
printf("%d\n",result);
// As I see it was mentioned that "%d\n" is a string,// here's the simplest algorithm for printing digits in a number.
// Extract one digit from the greatest position and continue up
// to the last digit in a number.
// Take negative numbers and throw them out the window.
if (result < 0) {
putchar('-');
result = -result;
}
// Our program currently supports printing numbers up to 10000.
int divisor = 10000;
// 000100 should print as 100 - we need to remember we printed non-zero
int was_not_zero = 0;
while (divisor != 0) {
// extract one digit at position from divisor
int digit = result / divisor % 10;
// if the digit is not zero,or
// we already printed anything
if (digit != 0 || was_not_zero) {
// print the digit
putchar(digit + '0');
was_not_zero = 1;
}
// the next digit will be to the right
divisor /= 10;
}
putchar('\n');
}
,
#include <string.h>
#include <stdio.h>
void operate(int * sum,int * n,char todo) {
if (todo == 1) *sum += *n;
else if (todo == -1) *sum -= *n;
printf("%s %d\n",todo == 1 ? "ADD :" : "SUB :",*n);
*n = 0;
}
int main()
{
char * problem = "10+13-12+25-5+100";
int len = strlen(problem);
int i=0;
char c;
int n = 0;
int sum = 0;
char todo = 1;
while(i < len)
{
c = problem[i++];
if (c < 48 || c >= 58)
{
// Adds or subtracts previous and prepare next
operate(&sum,&n,todo);
if (c == '+') todo = 1;
else if (c == '-') todo = -1;
}
else
{
// Collects an integer
if (n) n *= 10;
n += c - 48;
}
}
operate(&sum,todo); // Last pass
printf("SUM => %d\n",sum); // => 131
return 0;
}
,
#include <stdio.h>
void do_operation(char next_operation,int * result,int * number){
if (next_operation == '+'){
*result += *number;
*number = 0;
} else if (next_operation == '-'){
*result -= *number;
*number = 0;
} else {
printf("Unknown operation error.");
}
}
int main(int argc,char *argv[]){
char c;
int number = 0;
int result = 0;
char next_operation = '+';
do {
c = getchar();
if( c >= '0' && c <= '9' ){
number = number * 10 + c - 48;
} else if (c == '+'){
do_operation(next_operation,&result,&number);
next_operation = '+';
} else if (c == '-'){
do_operation(next_operation,&number);
next_operation = '-';
} else {
do_operation(next_operation,&number);
}
} while (c != '\n');
printf("%d",result);
}