我是c语言学习的初学者,我有一个问题
我必须编写以下代码:用户输入数学表达式,例如2+3*7
,代码应发送结果并考虑*
和/
的优先级。
我想在第一步中将用户的表达式输入一个char数组(禁止使用字符串)。
int counter=0;
char test[50],input;
while (counter < 50 && scanf("%c", &input) != EOF ){
test[counter] = input;
counter++;
}
for (i = 0; i < counter; i++){
printf("%c ", test[i]);
}
但是当用户输入时代码没有退出循环。怎么了?
我的第二个问题是,如果我不能使用字符串,那么将表达式输入char数组是个好主意吗?
我能用这种方式获得表达式的所有字符吗?
答案 0 :(得分:1)
但是当用户输入时代码没有退出循环。
您的代码不会退出循环,直到获得EOF(这通常意味着用户按下Ctrl + D)或输入了50个字符,而不是输入。如果要在用户按Enter键时结束,则需要检查最后一个字符输入是否为换行符。
此外,如果您一次只读一个字符getchar
可能比scanf更好。
读入一个char数组很好,只要你不能一次获得比缓冲区大小更多的字符,并确保你永远不会溢出缓冲区。
修改的
如果要求你不能使用字符串只是意味着你不能使用string.h,那么表达式中就不允许使用空格了(所以&# 34; 4 + 5&#34;有效,但&#34; 4 + 5&#34;不是,你可以这样做:char test[51],input;
scanf("%50s" &input);
printf("%s", input);
test
中的额外字符用于空终止符。
答案 1 :(得分:1)
但是当用户输入时,代码没有退出循环。
如果你想在ENTER键之后断开循环,你必须在你的情况下检查:
while (counter < 50 && scanf("%c", &input) != EOF && input != '\n' ) {
...
}
我的第二个问题是输入表达式是否是个好主意 如果我不能使用字符串进入char数组?
是。没关系。 C字符串和char数组之间没有什么区别(例如终止NUL字节)。因此,如果您不能使用fgets(str, sizeof str, stdin);
或scanf("%s", buf);
等字符串/行读取功能,那么您没有太多选择。
答案 2 :(得分:1)
您正在为scanf()
测试EOF
,这是对错误或文件结尾的测试,否则scanf()
会返回与成功转换的格式字符串匹配的字段数。在这种情况下,当输入来自控制台时它不会失败,因为%c
将匹配任何字符,如果没有字符存在,scanf()
将无限期地在控制台上等待 - 您可以将EOF注入控制台输入,但在这种情况下似乎不太可能。
scanf()
,更简单的getchar()
就足够了:
do
{
input = getchar() ;
test[counter] = input;
counter++;
} while( counter < sizeof(test) && input != '\n' ) ;
请注意,与原始代码一样,这不会添加nul终结符(因此在这个意义上它不是“字符串”)。
由于对明显使用stdio的哪些部分有些不合理的限制:
do
{
scanf( "%c", &input ) ;
test[counter] = input;
counter++;
} while( counter < sizeof(test) && input != '\n' ) ;
答案 3 :(得分:0)
你基本上需要写一个parser。您可以先拥有一些lexer(从字符流中提供令牌流)。然后,从一个标记流中,您的解析器将在内存中构建abstract syntax tree,或者它(在您的简单表达式中没有变量的表达式)在解析期间计算表达式。任何关于编译器的好书(例如dragon book)都会详细解释这一点。
有几种工具可用于生成解析器&amp;词法分析器。它们(夸张地)被称为compiler-compilers(但它们应该被称为解析器生成器)。 GNU bison就是这样一个工具。但您可以考虑ANTLR(可能是某些旧版本,ANTLR2或PCCTS)
您想要达到的目标是非常标准的练习。在bison
的文档中给出了example (calc
); recursive descent parser wikipage也有非常相似的代码。
具体关于scanf
,请阅读scanf(3)&amp;的文档。 getchar(3)(以及ungetc
....)您可以使用getline(3)(或者甚至是终端上的readline(3))阅读整行(以便更轻松地解析它),或者fgets(3) ...
答案 4 :(得分:0)
但是当用户输入时代码没有退出循环。
输入或'\n'
是有效的char
,可以使用scanf("%c", &input)
阅读。只需阅读'2'
和'+'
即可。
我的第二个问题是,如果我不能使用字符串,是否最好将表达式输入char数组?
是的,这是合理的。代码需要1)不存储char
超过数组大小2)跟踪数组中使用的元素。
我可以用这种方式获取表达式的所有字符吗?
如果您无法使用 stings ,也许您无法使用"%c"
。使用fgetc(),fputc()
#define N 50
int counter=0;
char test[N];
int input; // use int to distinguish EOF from a character.
while (counter < N && (input = fgetc(stdin)) != '\n' && input != EOF) {
test[counter] = input;
counter++;
}
for (i = 0; i < counter; i++){
fputc(test[i], stdout);
}
答案 5 :(得分:0)
请注意,C本身没有string
数据类型 ;在C中,字符串只是由0值字节(或多字节字符串的字节序列)终止的字符值序列。字符串存储作为char
的数组,但不是char
的每个数组都包含字符串。
如果您只是想从标准输入中获取一系列字符以进行进一步解析,这可能是最简单的方法:
char buffer[N]; // where N is large enough for one line's worth of input;
// let's call it 80 for now.
while ( fgets( buffer, sizeof buffer, stdin ) )
{
// process buffer
}
fgets
会将标准输入流中的字符读取到buffer
,直到它看到换行符(如果有空间,它将存储到buffer
中)或读取{{1}字符。 sizeof buffer - 1
将始终向缓冲区写入0字节以终止字符串。因此,例如,如果您的缓冲区大小为10个字符,并且您键入“2 + 3 * 4 Enter ”,那么fgets
将包含buffer
;没有足够的空间来存储换行符,但字符串是0终止的。
{'2', ' ', '+', ' ', '3', ' ', '*', ' ', '4', 0}
如果无法从流中读取输入,则会返回fgets
,因此上面的循环将一直运行,直到出现读取错误或直到NULL
检测到EOF条件。
...然而
处理这种情况的常用方法是在输入和处理过程中一次读取一个字符;这样您就不必担心放置足够大的缓冲区来容纳整个表达式,只需要足够大的缓冲区来处理较大表达式(数字和运算符)中的标记。