ページ 11

while(scanf("%s",s) != EOF)というコードについて

Posted: 2016年11月05日(土) 20:26
by range
競技プログラミングを始めたのですが、その参考書のコードについて質問です。
逆ポーランド記法を実装する問題なのですが、1行に空白区切で式を入力して改行すると次の行に結果を表示したいのですが、その空白区切の文字列の読み込みの終了判定のコードがうまく動きません。参考書の解答例の通りに書いたのにです。

コード:

while(scanf("%s",s) != EOF)
[\code]
という条件があり、scanfがEOFを返すのはエラーが起こった時のようなのでよく考えたら1行の終わりを判定するのはこれでは無理ではないかと思っています。しかし、参考書には解答例としてこのコードが書いてあるので困っています。
まず、上記のコードを書いた時にどういったことが起こると終了するのかということを教えて欲しいです。また、別の方法で文字列を空白区切に入力して、読み込むにはどのようにすれば良いか、できれば教えてください。
よろしくお願いします。

Re: while(scanf("%s",s) != EOF)というコードについて

Posted: 2016年11月05日(土) 20:31
by range
ちなみにその参考書は「プログラミングコンテスト攻略のためのアルゴリズムとデータ構造」です

Re: while(scanf("%s",s) != EOF)というコードについて

Posted: 2016年11月05日(土) 21:16
by みけCAT
range さんが書きました:まず、上記のコードを書いた時にどういったことが起こると終了するのかということを教えて欲しいです。
標準入力ストリームの最後まで読んだ後にscanf()で次の文字列を読もうとするとEOFが返るので、条件が偽になり、ループから抜けます。
range さんが書きました:また、別の方法で文字列を空白区切に入力して、読み込むにはどのようにすれば良いか、できれば教えてください。
1行ずつ読みたいなら、1行ずつ読めばいいでしょう。

コード:

#include <stdio.h>
#include <string.h>

int main(void) {
	/* スタックオーバーフローを避けるためstaticを付けて静的領域に置く */
	static char buffer[10000000]; /* 十分大きな要素数を確保する */
	while (fgets(buffer, sizeof(buffer), stdin) != NULL) { /* 1行読む */
		int count = 0; /* サンプルの処理用 */

		char *s = NULL; /* 分割した1トークンの位置を格納する */
		/* 空白で分割する */
		/* 第1引数は最初はbufferを、次以降はNULLを渡す */
		while ((s = strtok(s == NULL ? buffer : NULL, " \t\n")) != NULL) {
			/* 必要に応じた処理をする */
			printf("%d : %s\n", count++, s);
		}
		/* 必要に応じた処理をする */
		puts("-----");
	}
	return 0;
}

Re: while(scanf("%s",s) != EOF)というコードについて

Posted: 2016年11月05日(土) 21:25
by みけCAT
range さんが書きました:1行に空白区切で式を入力して改行すると次の行に結果を表示したいのですが、その空白区切の文字列の読み込みの終了判定のコードがうまく動きません。参考書の解答例の通りに書いたのにです。
「プログラミングコンテスト攻略のためのアルゴリズムとデータ構造 逆ポーランド記法」でググったところ、
プログラミングコンテスト攻略のためのアルゴリズムとデータ構造 - 渡部有隆 - Google ブックス
が見つかりました。
この82ページの「4.2 スタック」に書かれている逆ポーランド記法の問題は
入力 1つの数式が1行に与えられます。連続するシンボル (オペランドあるいは演算子)
   は1つの空白で区切られた与えられます。

出力 計算結果を1行に出力してください。
というものでした。
このプレビューではこの問題に対するコードは読めず、
range さんが書きました:

コード:

while(scanf("%s",s) != EOF)
[\code][/quote]
が使われているかはわかりませんでしたが、
rangeさんが用いた「参考書の解答例」は本当に「1行に空白区切で式を入力して改行すると次の行に結果を表示」という仕様のコードですか?
そもそも目指す仕様が違うコードであれば、動作結果も当然違うことが予想されるでしょう。

Re: while(scanf("%s",s) != EOF)というコードについて

Posted: 2016年11月05日(土) 22:37
by range
みけCATさん、ありがとうございます。
入力のストリームが終端まで行けば終了するということで、入力してからCtrl+Dすると計算結果は出ました。
そして、これはAOJという競技プログラミングのジャッジサービスの問題の解説をしてる書籍なのですが、試しにコードを提出してみたら成功しました。今までの問題は、標準入力で1行に入力してEnterを押すと結果を出力する問題ばかりだったので自分の環境で結果を確認してから提出していたのですが、今回確認しても結果が出てこないので悩んでいました。サービスの方でどういった処理がなされているのかわからないですが、どうやら入力の終わりは改行ではなかったようです。私があまりよくわかっていませんでした。しかし、今回私の知りたかった方法のやり方をコード付きで教えてくださってとても感謝しています。
一応、書籍そのままのコードではないですがACしたコードを貼ります。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

int stack[1000],top=0;

void push(int x)
{
	stack[++top] = x;
}

int pop()
{
	top--;
	return stack[top+1];
}

int main()
{
	char s[100];
	int x,y;

	while(scanf("%s",s) != EOF){
		if(s[0] == '+'){
			x = pop();
			y = pop();
			push(x + y);
		}else if(s[0] == '-'){
			x = pop();
			y = pop();
			push(y - x);
		}else if(s[0] == '*'){
			x = pop();
			y = pop();
			push(x * y);
		}else{
			push(atoi(s));
		}
	}

	printf("%d\n",pop());

	return 0;
}