質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.62%

ungetc の使い道

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 577

doraemon1106

score 18

main()

{

int c;

long

x, a, b;

init();

while ((c = getchar()) != EOF) {

if (isdigit(c)) {

ungetc(c, stdin);

scanf("%ld", &x);

push(x);

} else {

switch (c) {

case '+':

b = pop(); a = pop();

push(a + b);

break;

case '-':

b = pop(); a = pop();

push(a - b);

break;

case '*':

b = pop(); a = pop();

push(a * b);

break;

case '/':

b = pop(); a = pop();

push(a / b);

break;

case '\n':

if (! empty())

printf("答えは%ldです\n", pop());

init();

break;

case ' ':

case '\t':

/*

何もしないで読みとばす */

break;

default:

printf("不正な文字がありました。\n");

printf("入力しなおして下さい。\n");

while ((c = getchar()) != EOF && c != '\n')

;

break;

}

}

}

}

少し省いてますが、逆ポーランド記法を実現するためにスタックを用いています。

この序盤に出てくるungetc(c.stdin)の存在意義がわかりません。ストリームから読み込んだ文字を戻すという事がいまいち掴めないのです。その後のscanfで打ち直してるのともリンクしません。ご回答よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • otn

    2019/05/05 14:47

    見にくいので、コードブロックで囲む、つまり、プログラムの前に
    ```C
    という行を置いて、プログラムの後に、
    ```
    という行を置いて、ちゃんとインデントが分かるようにしてプログラムを記述してください。

    キャンセル

回答 1

checkベストアンサー

+4

例えば、123という入力があったとして、getchar1を読んで数字だと判断してscanfすると、読み込むのは23となり、1が欠けてしまいます。
そこで1をストリームに戻してやると、次のscanf123が読めます。

コメントを読んでの追記

プログラムで端末から入力するというのがどういうことか理解できていないようなので、少し説明します。
(面倒くさいので、複数バイト文字のことは考えず、以下の説明では文字とバイトを同じような意味で使っています)

端末と、自分で書いたプログラムの間に、ライブラリで実現されているバッファという文字列領域があります。
バッファには、端末から文字が入力され、自分で書いたプログラムのgetcharscanfは、バッファにある文字を変数に代入します。
端末で文字を打って、Enterを押すと、文字が行単位でバッファに追加されます(改行コード付き)。
プログラムでgetcharすると先頭の1バイトをプログラムが得て、バッファからはその1バイトが消えます。
プログラムでscanfすると、フォーマット文字列に該当するバイト列が(必要なら変換されて)変数に入ります。その分のバイト列はバッファから消えます。

ここまで理解できたとして、動作を説明します。
まず最初に実行される入力関数は、c = getchar()のところです。これは、「バッファから1バイトよこせ」という命令ですが、バッファは最初は空です。空のバッファから読もうとした場合は、端末は1行入力状態になり、打った文字列はバッファに入ります。ここで、123Enterと打ったとします。この瞬間のバッファは"123\n"です。
で、getchar()は先頭の'1'を取ってcに代入します。この時点のバッファは"23\n"です。
isdigit(c)は真なので、ungetc(c,stdin)します。cをバッファに返すので、この時点でのバッファは"123\n"に戻ります。で、scanf("%ld",&x)が実行されますので、"%ld"によって文字列"123"long int型に変換されてxに入ります。この時点のバッファは"\n"ですので、次にgetchar()するとc'\n'になり、バッファは""つまり空になります。さらにgetchar()を行うと・・・・最初に戻る。

以下補足(蛇足?):
入力が端末じゃなくて、ファイルの場合は、バッファは行単位じゃなくて4096バイトとか8192バイトとかの領域になります。
また、端末属性を変更すると、行単位じゃなくてキー1つ単位での入力も可能です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/05 20:19

    ご苦労様。

    キャンセル

  • 2019/05/05 22:10

    かなり理解しました。何も理解できてなかったです。助かりました!ありがとうございました😊

    キャンセル

  • 2019/05/05 22:23

    ライブラリの実装はまた違ったりしますが、意味的には回答したとおりです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る