プロが教えるわが家の防犯対策術!

こんにちは
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;
}

A 回答 (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;
}
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/11/16 10:58

No.4です。

再コメントします。

今、手元にK&Rがないので、getop()の呼び出し元の処理を
私の方で確認できないのですが、getop()の戻り値がNUMBER以外の場合に
getopに指定した配列の内容を参照しないようになっているのであれば、
(1)はそのサンプルコーディングを実行する上で必須のコードではないと
考えてよいと思います。

その場合、(1)が必要か否かは、作者がgetop()の関数仕様を
どのように考えているか次第ということになると思います。
(戻り値がNUMBER以外の時に、文字列sは不定値になるか否か。
または、戻り値がNUMBER以外の時に文字列sの参照を許可するか否か。)

なお、仕様で扱いが決まっていない場合でも、配列sを中途半端な
状態で放置せず、文字列として終端をきちんと処置しておくのは、
行儀がよく安全なコーディングであると言えると思います。
    • good
    • 0
この回答へのお礼

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

とても参考になりました。
どうも有難うございました!

お礼日時:2009/11/16 11:01

(1)の件について、


例えば「+」という演算子の入力があった場合、
getop()は、配列sに"+"という文字列を設定して
返却することが意図されていると思います。

s[1] = '\0';
は、"+"のような1文字の文字列を形成するために必要な
文字終端設定処理です。

もし
s[1] = '\0';
がない場合、s[1]には以前に使用したゴミデータが入ったままで、
正しく"+"という1文字の文字列にならない可能性があるので、
(1)は必要です。

この回答への補足

if( !isdigit(c) && c != '.')
return c;        /* 数ではない */

の部分は、文字列sを返しているのではなく、文字cを返しています。

文字列sを返しているのであれば仰るとおりなのですが、ここでは文字cを返しているので、仰るようにはならないように思います。

補足日時:2009/11/15 21:38
    • good
    • 0

> s[1] = '\0'は不要なのではないのでしょうか?



そう思うならやってみればいい。

この回答への補足

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

補足日時:2009/11/15 20:50
    • good
    • 0

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

    • good
    • 0
この回答へのお礼

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

でも、(1)の方はまだ分からないでいます。

お礼日時:2009/11/15 17:44

(1) 文字列の末端を示すため。


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

この回答への補足

仰ぎ見るepisteme先生からさっそくご回答をいただきまして、ありがとうございます。

おそれながら、(1)の
while( (s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';       /* ← (1) */

は、文字(数字か演算子)に先立って入力される不要な空白文字を読み飛ばすために行われている処理なので、s[1] = '\0'は不要なのではないのでしょうか?

このプログラムは、逆ポーランド記法で計算する簡単な計算機で、

入力: 1   2   +
出力: 3

のように動作するものです。


そう考えると、(2)の疑問が出てきました。

補足日時:2009/11/15 14:32
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/11/16 11:04

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!