fc2ブログ
 カレンダー

11月 │2023年12月│ 01月
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -

 プロフィール

はしもと

Author:はしもと
ユーザインタフェース系のお仕事をしてます.関心領域は画像処理,拡張現実感,ヒューマンコンピュータインタラクション,エンタテインメントコンピューティングあたり.モノ書きもやってます.

 工学ナビ

工学ナビは工学系の技術のチュートリアルを扱うサイトです.

 作ったもの

 Twitter

 

 天気予報


 ブログ内検索

 カテゴリー

最新コメント

 RSSフィード

 リンク

このブログをリンクに追加する




工学ナビの中の人 はしもとのブログです. いろんなコトを研究的,工学的な視点で見つめます.
scanfは使うな
 2chの「C言語なら俺に聞け!」スレは,2000年9月に初代スレがたってから現在Part117に至る長寿スレ.これの過去ログがまた面白い.
 ときにスレ内で勃発する,質問者置いてけぼりの住人同士の論争(Part91の69以降とか)を読んでいると,まるで喧嘩を見ている野次馬のような気分になり,別な意味で楽しめます.技術系のスレでもこの手の祭が発生するので油断できませんw

 さて,このスレはいわゆる質問スレの形をとってはいるものの,多くの場合質問に対する回答はアドバイスではなくダメ出しで返ってきます.そしてこのスレで頻出するお約束のレスがこれ.

scanf使うなボケ
解決策:scanfを使わない
うまくいかない理由:scanfを使っているから

C言語入門で必ず教えられるscanfですが,プログラマの間ではもはや禁じ手として
扱われています.それはなぜか?

・入力をその場で解釈しながら処理するのでエラーチェックに対応できない
・scanfそのものがエラーの原因になる

scanfのダメさ加減(仕様)を見るために以下のようなプログラムを書いてみます.

int main(void)
{
       int a;
       char b;
       scanf("%d",&a);
       scanf("%c",&b);
       printf("input1:%d\n",a);
       printf("input2:%c\n",b);

       return 0;
}


 最初のscanfで数値を読み込み,2個目のscanfで文字を読み込む(つもりの)プログラムです.しかしこれを実行すると数値を入力してエンターを押した瞬間,次の入力を待たずにprintfが実行され,終了します.

>1234
>input1:1234
>input2:
>
>Press any key to continue


1個目の入力時のエンターを2個目のscanfが「改行」という文字として拾ってしまうのでこういうことが起こります.さらに面白いことに「1234a」と入力すると次のようなことになります.

>1234a
>input1:1234
>input2:a
>Press any key to continue


1234aのうち1234が数値として処理され,残りのaが2個目のscanfで文字として処理されたようです.では単に「a」だけ入力した場合はどうなるでしょうか?

>a
>input1:-858993460
>input2:a
>Press any key to continue


1個目のscanfでは数値の処理に失敗しておかしな値を吐いています.

 こんな具合にscanfはコーディング次第で結構危ない挙動をしてくれます.scanfの代わりとしては,fgetsを使って入力の1行全体を読み込み,それをsscanfで分解して読み込むという方法があるようです.(※ちなみにここでfgetsではなくgetsを使ってしまうと読もうとしているバッファの大きさを指定できないため,バッファがあふれてしまう危険があるので注意.)

 scanfはちょこっとテストプログラム作るときには便利ですが,上のような危険も孕んでいることを理解した上で使いましょう.というか使わないのが一番なんですけど.

この辺,GUIのプログラムだと無縁ですね.


【参考】
C言語なら俺に聞け! 過去ログ置き場
scanf を使わないコンソール入力
C言語 FAQ 日本語訳


Cプログラミング診断室―さらに美しく健康的なプログラムのために
藤原 博文 (著)

出版社: 技術評論社
改訂新版 (2003/07)





この記事に対するコメント



この記事に対するコメントの投稿














管理者にだけ表示を許可する


この記事に対するトラックバック
トラックバックURL
→http://kougaku.blog28.fc2.com/tb.php/41-136c4db7
この記事にトラックバックする(FC2ブログユーザー)

scanfからfscanf,fgetsへ

本当に備忘録なので,初歩的なことで恐縮です. C言語の「scanf」は使わずに,代わりにfscanf関数やfgets関数で代用しよう. int num; fscanf(stdin,"%d",&num)... プログラミングの試し【2010/07/07 02:55】