我正在寻找一个可以将字符串表达式计算为整数的函数,例如 f.e.:
10/2+4*3-(12+5); //Equals 0
转换为
int
类型的对象,其值为 0
。
复杂操作的功能会更好,即使这不是当时的需要:
2^(1/2)-99
标准 C 库(C89、C90,如果已编译)中是否定义了此类定义?
有没有非标准库有这样的功能?
表达式支持的字符越多越好。
但即使是像 +、-、*、/、() 这样的基本操作也可以。
标准 C 库(C89、C90,如果已编译)中是否定义了此类定义?
不,即使在更新的 C11 或 C18 标准库中也没有。
有没有非标准库有这样的功能?
我也找不到。您必须编写自己的函数来完成此任务。
也许在第一步扫描字符串并将其中的每个值存储到单独的字符串中。
正如我在评论中已经建议的那样,
strtol
用于将字符串中的像11
这样的整数值转换为int
类型的值。您可能需要利用它。库中还有一个 atoi
函数,可将字符串内的整数值转换为 int
,但该函数更容易出错,不应使用。
算术运算符也应存储在单独的字符串中,但稍后由自制例程进行评估。
但是可以在这里找到很好的示例和建议,其中用户被问到类似(如果不相同)的问题:
标准 C 库中没有计算算术表达式的函数。这是一个针对
evald
结果的 double
函数的快速而肮脏的实现。它支持 5 种经典二元运算 +
、-
、*
、/
、%
以及 ^
求幂,处理任何深度的括号,但需要更多的一元 +
和 工作-
。
很容易转换为纯整数算术。
这是代码:
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
double evald(const char *s, char **endp) {
struct operand {
double val;
int op, prec;
} stack[4], *sp, x;
char *p;
for (sp = stack;;) {
if (*s == '(') {
x.val = evald(s + 1, &p);
s = p;
if (*s == ')')
s++;
} else {
x.val = strtod(s, &p);
s = p;
}
while (isspace((unsigned char)*s))
s++;
switch (x.op = *s++) {
case '^': x.prec = 3; break;
case '*':
case '/':
case '%': x.prec = 2; break;
case '+':
case '-': x.prec = 1; break;
default: x.prec = 0; x.op = 0; s--; break;
}
while (sp > stack && x.prec <= sp[-1].prec) {
switch ((--sp)->op) {
case '^': x.val = pow(sp->val, x.val); break;
case '*': x.val = sp->val * x.val; break;
case '/': x.val = sp->val / x.val; break;
case '%': x.val = fmod(sp->val, x.val); break;
case '+': x.val = sp->val + x.val; break;
case '-': x.val = sp->val - x.val; break;
}
}
if (!x.op) break;
*sp++ = x;
}
if (endp) *endp = (char *)s;
return x.val;
}
int main(int argc, char *argv[]) {
if (argc > 1) {
for (int i = 1; i < argc; i++) {
printf("%s -> %.17g\n", argv[i], evald(argv[i], NULL));
}
} else {
char buf[100];
for (;;) {
printf("eval> ");
fflush(stdout);
if (!fgets(buf, sizeof buf, stdin) || (buf[0] == 'q' && buf[1] == '\n'))
break;
printf(" -> %.17g\n", evald(buf, NULL));
}
}
return 0;
}
以下是我向 RobertS 的解析器添加一元运算符的方法。在第一次进入或递归解析循环之前的 ()' 内部内容时,您将 0 与运算符一起以最高优先级压入堆栈。然后它可以处理:-(2-5)^2,即-(-3),然后对9进行平方,甚至-((2-5)**2)并得到-9的值。每次堆栈推送都会将一个值/运算符(按该顺序)放入堆栈中,并将下一对与堆栈顶部进行比较。 (我花了一段时间掌握这个算法的窍门)。
此外,您还可以通过将函数简单地视为 () 来添加函数,一旦递归求值,就会在被推入堆栈之前通过函数运行。
if (c == '+' || c == '-') { // check for initial uniary+ or -
x.val = 0.0;
x.op = c;
x.prec = 3; // give it highest priority
*sp++ = x; // pretend we started with a 0, so it's 0+... or 0-...
s++;
}