【发布时间】:2017-10-21 05:11:28
【问题描述】:
所以我为一个简单的逆波兰计算器编写了一个代码,它只适用于使用命令行参数的正数。它将数字存储在堆栈中。 push 和 pop 的函数位于单独的源文件中。
我还编写了另一个程序来检查我之前程序的控制流。
这是第一个程序:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
void push(double);
double pop(void);
int main(int argc, char *argv[])
{
int c;
double op2;
while(--argc>0 && (c=(*++argv)[0]))
if(isdigit(c))
push(atof(argv[0]));
else if(c=='+')
push(pop()+pop());
else if(c=='-')
{
op2=pop();
push(pop()-op2);
}
else if(c=='*')
push(pop() * pop());
else
{
op2=pop();
push(pop()/op2);
}
printf("\n%f\n", pop());
return 0;
}
在我运行这个程序之后,所有的操作符都工作了,除了'*'。例如,如果我的输入是“./pcalc 2 3 *”,那么我得到的输出是:error: stack emptyerror: stack emptyerror: stack emptyerror: stack empty
-nan
如果我在 while 循环中交换条件,像这样while((c=(*++argv)[0]) && --argc>0)
然后我收到所有运营商的“分段错误(核心转储)”消息。
为了了解我的程序的控制流程,我把部分代码改成了这样:
while(--argc>0 && (c=(*++argv)[0]))
if(isdigit(c))
printf("\nentry1\n");
else if(c=='+')
printf("\nentry2\n");
else if(c=='-')
printf("\nentry3\n");
else if(c=='*')
printf("\nentry4\n");
else
printf("\nentry5\n");
程序的其余部分与第一个类似。在将输入作为 ' ./pcalc 2 3 * ' 时,我得到以下输出:
entry1
entry1
entry5
entry5
entry5
entry5
entry5
error: stack empty
0.000000
这意味着控制没有转到星号的大小写,而是转到了 else 部分。
当我交换while循环的条件时,我得到的输出与上面相似(对于所有运算符,它显示控制流,对于'*',它显示与上面相同的错误),除了它没有' 不显示任何运算符的堆栈空错误,而是显示分段错误(核心转储)消息。
所以这就是我想问的:
1)我的第一个程序适用于所有运算符,除了'*'。可能是什么原因?为什么控制权转到了else部分?
2) 交换条件后,我访问了哪些我没有权限的内存?如果它是NULL,那么不应该打破while循环并继续吗?
PS。这是我的第一个问题,所以如果我的写作风格有任何错误,或者问题太长,请告诉我!我们从错误中吸取教训 :)
还有,我的编译器-GCC,OS-Ubuntu。
【问题讨论】:
-
旁注:您提到您的
push和pop函数位于单独的源文件中。确保将它们保留为函数。也就是说,无论你做什么,都不要使用像#define pop() stack[--stackp]这样的函数式宏。否则,当您编写push(pop()+pop())之类的内容时,这将是未定义的行为。 (但只要push和pop是函数,就可以了。) -
出于调试目的,在处理它们之前尝试打印出所有命令行参数。您可能会看到与预期不同的东西,尤其是从命令行运行程序时。
-
@xing 太好了,谢谢!但是当条件互换时,段错误的原因可能是什么?
-
@AkhilAbraham “段错误的原因是什么?”尝试为
else if(c=='/')添加一个显式测试,并在最后加上一个包罗万象的else,它只打印“意外输入”之类的东西。 -
while(--argc>0 && (c=(*++argv)[0]))如果我在代码审查中看到这一点,那么您正在重写该行以使其可读。
标签: c pointers segmentation-fault command-line-arguments