逆ポーランド記法の電卓
Posted: 2014年7月27日(日) 17:51
C言語初心者です。プログラミング言語C 第2版(K&R)の内容について質問させていただきます。 今回の内容は質問していいようなものなのか、と躊躇したのですが…どうしてもわかりませんでした。
P92~96の逆ポーランド電卓プログラムです。スタックにプッシュ、ポップするやつです。
「12-45+*」でトレースしようとするのですが、まずスタックに格納される値が「12.0」になってしまうのです。
以下、コードを部分的に書き出してトレースの様子を記述します。
getop関数です。
「12-45+*」でトレースするとこのgetop関数でs[]に'1''2''\0'が格納され、'-'がbuf[]に格納されるはずです。
そしてmain()のswitch内でatof(s)が12.0を返すのです。何故?
以下、atof(s)の中身を記述します。P87にものっています。
繰り返しますが、わからないのはgetop関数内の挙動とpush(atof(s));の部分です。どちらかを誤って解釈しているのだと思うのですが…
P92~96の逆ポーランド電卓プログラムです。スタックにプッシュ、ポップするやつです。
「12-45+*」でトレースしようとするのですが、まずスタックに格納される値が「12.0」になってしまうのです。
以下、コードを部分的に書き出してトレースの様子を記述します。
/* 逆ポーランド電卓プログラム */
main()
{
int type;
double op2; /* -と÷の被演算数を区別するためのもの */
char s[MAXOP]; /* MAXOP == 100 */
while((type = getop(s)) != EOF){
switch (type){
case NUMBER:
push(atof(s)); // atof()は文字列sをdouble型に変換して返します
break;
/* 以下省略。わからないのはgetop関数内の挙動とpush(atof(s));の部分ですので。 */
/* getop: 次の演算子あるいは数値の被演算数をとってくる */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == 't')
;
s[1] = '\0';
if ( ! isdigit(c) && c != '.') // isdigit()は '0' <= c && c <= '9' の真偽を返す関数です
return c;
i = 0;
if (isdigit(c)) /* 整数部を集める */
while(isdigit(s[++i] = c = getch()))
;
// getch()は不要な文字を読み戻す関数で、記述しませんがchar buf[]に演算子が格納されていなければgetchar()を返します
if (c == '.') /* 小数部を集める */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
// ungetch()は文字を入力に戻します。getch()に演算子が渡されるとbuf[]に格納され、ungetch()がそれを返します
return NUMBER; /* NUMBER == '0' です。main関数に数が集められたという目印を返します
}
そしてmain()のswitch内でatof(s)が12.0を返すのです。何故?
以下、atof(s)の中身を記述します。P87にものっています。
#include <stype.h>
/* atof: 文字列sをdoubleに変換する */
double atof(char s[])
{
double val, power;
int i, sign;
for(i = 0; isspace(s[i]); i++) /* 空白を飛ばす */
;
sign = (s[i] == '-') ? -1 : 1;
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; isdigit(s[i]); i++){
val = 10.0 * val + (s[i] - '0');
power *= 10.0;
}
return sign * val / power;
}