• ベストアンサー

K&Rのp.95のgetop(char s[])

こんにちは K&Rを読んでいるのですが、p.95のgetop(char s[])について質問します。 (1)関数本体の4行めにある    s[1] = '\0'; は、何のためにあるのでしょうか? (2)9行めと12行めで、    while( isdigit(s[++i] = c = getch()) ) とあるのですが、なぜs[i++]とせずにs[++i]として、cを格納するs[i]を、s[0]ではなくてs[1]から始めているのでしょうか? /* getop: 次の演算子あるいは数値の被演算数をとってくる */ int getop(char s[]) { int i, c; while( (s[0] = c = getch()) == ' ' || c == '\t') ; s[1] = '\0';       /* ← (1) */ if( !isdigit(c) && c != '.') return c;        /* 数ではない */ i = 0; if(isdigit(c))      /* 整数部を集める */ while( isdigit(s[++i] = c = getch()) )     /* ← (2) */ ; if(c == '.')       /* 小数部を集める */ while( isdigit(s[++i] = c = getch()) )     /* ← (2) */ ; s[i] = '\0'; if(c != EOF) ungetch(c); return NUMBER; }

質問者が選んだベストアンサー

  • ベストアンサー
  • php504
  • ベストアンサー率42% (926/2160)
回答No.6

以下のような場合はdefaultでsも使ってるので'\0'は必要でしょう while((type = getop(s)) != EOF) { } switch (type) { case NUMBER: push(atof(s)); break; case '+': push(pop() + pop()); break; case '*': push(pop() * pop()); break; case '-': op2 = pop(); push(pop() - op2); break; case '/': op2 = pop(); if (op2 != 0.0) push(pop() / op2); else printf("error: zero divisor\n"); break; case '\n': printf("\t%.8g\n", pop()); break; default: printf("error: unknown command %s\n", s); break; }

template_i
質問者

お礼

演算子として'+'、'-'、'*'、'/'以外のものを指定した時に出力されるエラーメッセージをきちんと出すためにs[1] = '\0'としているということが分かりました。 おかげさまですっきりしました。 どうも有難うございました!

その他の回答 (5)

  • Lchan0211
  • ベストアンサー率64% (239/371)
回答No.5

No.4です。再コメントします。 今、手元にK&Rがないので、getop()の呼び出し元の処理を 私の方で確認できないのですが、getop()の戻り値がNUMBER以外の場合に getopに指定した配列の内容を参照しないようになっているのであれば、 (1)はそのサンプルコーディングを実行する上で必須のコードではないと 考えてよいと思います。 その場合、(1)が必要か否かは、作者がgetop()の関数仕様を どのように考えているか次第ということになると思います。 (戻り値がNUMBER以外の時に、文字列sは不定値になるか否か。 または、戻り値がNUMBER以外の時に文字列sの参照を許可するか否か。) なお、仕様で扱いが決まっていない場合でも、配列sを中途半端な 状態で放置せず、文字列として終端をきちんと処置しておくのは、 行儀がよく安全なコーディングであると言えると思います。

template_i
質問者

お礼

>配列sを中途半端な >状態で放置せず、文字列として終端をきちんと処置しておくのは、 >行儀がよく安全なコーディングであると言えると思います。 とても参考になりました。 どうも有難うございました!

  • Lchan0211
  • ベストアンサー率64% (239/371)
回答No.4

(1)の件について、 例えば「+」という演算子の入力があった場合、 getop()は、配列sに"+"という文字列を設定して 返却することが意図されていると思います。 s[1] = '\0'; は、"+"のような1文字の文字列を形成するために必要な 文字終端設定処理です。 もし s[1] = '\0'; がない場合、s[1]には以前に使用したゴミデータが入ったままで、 正しく"+"という1文字の文字列にならない可能性があるので、 (1)は必要です。

template_i
質問者

補足

if( !isdigit(c) && c != '.') return c;        /* 数ではない */ の部分は、文字列sを返しているのではなく、文字cを返しています。 文字列sを返しているのであれば仰るとおりなのですが、ここでは文字cを返しているので、仰るようにはならないように思います。

回答No.3

> s[1] = '\0'は不要なのではないのでしょうか? そう思うならやってみればいい。

template_i
質問者

補足

はい、いちおう自分ではやってはみたのですが、違いが出ないのです。 力不足ですみません。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

s[0]には空白を読み飛ばした後の非空白文字が入っています

template_i
質問者

お礼

確かにそうですね! なぜ(2)でs[++i]にしているのかが分かりました! ありがとうございます! でも、(1)の方はまだ分からないでいます。

回答No.1

(1) 文字列の末端を示すため。 (2) while( (s[0] = c = getch()) == ' ' || c == '\t') で入力された文字を書きつぶさないよう。

template_i
質問者

お礼

ご指導ありがとうございました。

template_i
質問者

補足

仰ぎ見るepisteme先生からさっそくご回答をいただきまして、ありがとうございます。 おそれながら、(1)の while( (s[0] = c = getch()) == ' ' || c == '\t') ; s[1] = '\0';       /* ← (1) */ は、文字(数字か演算子)に先立って入力される不要な空白文字を読み飛ばすために行われている処理なので、s[1] = '\0'は不要なのではないのでしょうか? このプログラムは、逆ポーランド記法で計算する簡単な計算機で、 入力: 1   2   + 出力: 3 のように動作するものです。 そう考えると、(2)の疑問が出てきました。

関連するQ&A