- ベストアンサー
【C言語】二重forループ内でscanfを使ってchar型変数に数値を入力すると、きちんとループ処理されないのはなぜ?
- char型変数に値を入力しているために、forループでiがきちんとインクリメントされません。
- 入力値は-128~127の値しか想定していないため、char型で宣言したことが原因です。
- int型で宣言すれば正常にループ処理が行われます。なぜchar型での挙動がおかしくなるのか知りたいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
scanfのマニュアルをよくよんでください。 フォーマット%dが要求するのはint型へのポインタです。 例え、実際にはchar型へのポインタであったとしても、きっちりint型の分の領域にデータが書き込まれます。その場合、char型より大きい分は変数の領域の外へ書き込まれることになります。 今回は、そのあふれた先が変数iの領域だったので、iが異常な値になったのでしょう。
その他の回答 (3)
- kmee
- ベストアンサー率55% (1857/3366)
4バイト単位のメモリアクセスをする32bitCPUを考えます。 1バイト単位では読み込みはできないので、C言語風に書くと char c = MEMORY[1] ; /* 1バイト目の1バイト分のデータを取り出す */ としたい場合には int a=MEMORY[0] ; /* 0~3バイト目を取り出す */ a >>= 8 ; /* 1バイト目にあたる部分を最下位へシフトする(リトルエンディアンの場合) */ char c = a & 0xff ; /* 余分なビットを0に消去する */ と、intなら1命令で済むところを3命令必要です。 CPUによっては、1命令で実行できる場合もあるし、実際に上のような3命令必要なものもあります。 また、1命令でできるの場合でも、intと同じ時間で実行できるものもあれば、内部で上のような処理をしていてintより長い時間がかかるCPUもあります。 また、コンパイラの種類やオプションによって、積極的に1命令のを使ったり、逆に(互換性等を考えて)1命令のものは使用しなかったり、します。 使用メモリ量は、たしかに考えなければなりません(特に、制限の多い組込みの分野では) しかし、ターゲットCPUやコンパイラの特性、ソフトのパフォーマンス等を十分に知った上で行わないと、節約した積もりが、かえって消費していた、ということになります。
補足
なるほど。 「それをわざわざchar型に制限するために、その為の処理コードが追加される可能性もあります。」 の意味が分かりました。どうやら素人がメモリの節約に気を使うのはやめた方が良さそうです。 本題以外の質問にまでご丁寧にお答え下さってありがとうございました。
- php504
- ベストアンサー率42% (926/2160)
scanfで%hhdが使えるコンパイラでしたらchar型にも代入できます でも使えないコンパイラのほうが多いですからscanfで直接char型へは代入できないと思っていたほうがいいでしょう scanfでは変換指定子と変数の型はプログラマの責任できちんとあわせましょう %dは整数型なら何でもいいと思っている人はよく見ますね short input; scanf("%hd", &input); なら使えると思います
お礼
>short input; >scanf("%hd", &input); のやり方を教えて下さりありがとうございました。
補足
scanf("%d", &input); を scanf("%hhd", &input); に試しに変更してみたところ、動作に変化はありませんでした。 short input = 0; scanf("%hd", &input); としたところ、正常に動作しました。 >%dは整数型なら何でもいいと思っている人はよく見ますね まさに私のことですね。 long型は %ld double型は %lf は知っていたのですが、char型の整数に関しては何も説明が無かったので、%d でいいのかと勝手に解釈していました。 でも、printf の場合はchar型を %d で出力したらint型と同じように整数が出力されるのはなぜなんでしょうね。 本質問と似た問題に直面したWebページを見つけたので、書いておきます。 http://www.play21.jp/board/formz.cgi?action=quote&resno=32617&id=dixq&quo=32622&lognum=100&from=all
- Wr5
- ベストアンサー率53% (2173/4061)
>scanf("%d", &input); で、"%d"によりint型分の領域に書き込もうとするから…です。 1リットルの入るコップに4リットルのペットボトルから飲み物入れたら溢れますよね? 使うのは1リットル分でも、そんなのお構いなしです。 たかだか変数1つをint型からchar型に変えたところで、スタックの使用量がほんの数バイト節約できるだけです。 # 処理系によっては次に配置するint型のアクセス効率のために余分にメモリをとっているかも知れません。 数値はchar型よりint型で扱う方がCPUにとって自然です。 それをわざわざchar型に制限するために、その為の処理コードが追加される可能性もあります。 int型が4バイトだとして…3バイト節約するために3バイト以上のコードが増えることは望ましい結果でしょうか?
お礼
>1リットルの入るコップに4リットルのペットボトルから飲み物入れたら溢れますよね? の例えがとても分かり易かったです。ありがとうございました。
補足
char型分の領域から溢れた分がint型分の領域に入って悪さをしていのですね。 >たかだか変数1つをint型からchar型に変えたところで、スタックの使用量がほんの数バイト節約できるだけです。 質問で書いた小さなプログラムではメモリの節約は無意味と言ってもいいでしょうが、非常に大きなプログラムの場合だとメモリは節約するに越したことはないと思うのですが、違うのでしょうか。「処理系によっては~~余分にメモリをとっているかも知れません。」と仰るように、処理系によるのですかね。 >それをわざわざchar型に制限するために、その為の処理コードが追加される可能性もあります。 質問の本題とは反れてしまいますが、プログラミング歴が浅いのでどのような場合がそれに当たるのか分かりませんので、簡単に教えてもらえないでしょうか。char型をint型にキャストする場合がそれに当たるのでしょうか。
お礼
>char型より大きい分は変数の領域の外へ書き込まれることになります。 >今回は、そのあふれた先が変数iの領域だったので、iが異常な値になったのでしょう。 の説明で、 i がおかしな値になっていることに合点がいきました。 ありがとうございました。
補足
なるほど、そういう訳でしたか。 同じように考えてみると、long型に入力する場合に %ld とするのは、long型の分の領域に書き込むためなのですかね。