良い質問のタイトルが思い浮かばず、分かりづらいタイトルで申し訳ありません、C言語について質問させて頂きます。
C言語の参考書を買って夏休み中にプログラムの勉強をしているのですが、何故動作するのかがわからない例があります、ソースは以下の通りです。
#include <stdio.h>
int main(void)
{
int i,ch;
int cnt[10] = {0};
while(1)
{
ch = getchar();
if (ch==EOF) break;
switch(ch)
{
case '0' : cnt[0]++;printf("%d\n",ch);break;/* printfは確認の為 */
case '1' : cnt[1]++;printf("%d\n",ch);break;
case '2' : cnt[2]++;printf("%d\n",ch);break;
case '3' : cnt[3]++;printf("%d\n",ch);break;
case '4' : cnt[4]++;printf("%d\n",ch);break;
case '5' : cnt[5]++;printf("%d\n",ch);break;
case '6' : cnt[6]++;printf("%d\n",ch);break;
case '7' : cnt[7]++;printf("%d\n",ch);break;
case '8' : cnt[8]++;printf("%d\n",ch);break;
case '9' : cnt[9]++;printf("%d\n",ch);break;
}
}
puts("数字文字の出現回数");
for(i=0;i<10;i++)
printf("'%d':%d\n",i,cnt[i]);
getchar();getchar();
return(0);
}
といったプログラムです。
実行し、数値を入力、CTRL+Zで入力を終了し、出現回数を表示させる、という動作自体は無事にできるのですが、何故chの値が変更していくのかがわかりません、数値を入力した時点で51や49といったそれぞれ違う数値が表示されるのですが、chの値を変更させる命令を、何が引き起こしているのかが理解できません、3(51)と判定されて同じ数が無限にカウントされないのは何故なのでしょうか・・・・?
また、その後の無限ループからの脱出をCTRL+Zがどうして引き起こすのかも理解できず困っています、教科書には「CTRL+Zは入力の終了を意味する」とあるのですが、これは一体どういう意味なのでしょうか、強制的に割り込んでEOFを代入するということなのでしょうか・・・?
お時間がある時にでも、教えて頂けると助かります、よろしくお願いします。
No.4ベストアンサー
- 回答日時:
>getchar関数とは入力した文字を順番に3、.、1、4、と返す関数ということなのでしょうか・・?
基本的にはそれで合ってます。
ただ、'3'、'.'、'1'、'4'という文字そのものを返す訳ではなく、アスキーコードを返します。
http://e-words.jp/p/r-ascii.html
平たくいうと、コンピュータは0と1の世界ですから、'a'などの文字も数値としてハードディスクに保存する必要があります。人間が見て分かる文字とコンピュータの世界のコードとの対応表がアスキーコード表です。
OSを始め様々なソフトが、この保存された数値を人間が見て分かりやすい文字に変換してくれてるわけです。
今回の例で言うと、入力された数値をアスキーコードではなく、配列の添字として使いたいので、
int index = ch - '0';
としています。
int index = ch - 48;
でもいいんですが、マジックナンバー(プログラム中に書かれた0, 1以外の数値)を嫌う人もいますので、'0'としています。
printfで%dで出力すると、アスキーコードの値がそのまま出力されます。
これを入力した文字そのものを出力したい場合は、%cを使用します。
No.6
- 回答日時:
ちょっと混乱の元になるかもしれませんが、豆知識として。
getchar()が返すのは、「キーボードから」入力した1文字ものではなく、「標準入力から」入力した1文字です。
標準入力は通常はキーボードに割り当てられているので、何もしなければ「キーボードから」になります。
実行ファイル < input.txt とすると、標準入力はファイル input.txt からになります。
別のコマンド | 実行ファイル とすると、標準入力は「別のコマンド」の標準出力に出力されたものになります。
getcharは入力の終わりが来たらEOFという特別な値を返して報せます。このプログラムでは、そのEOFが返ってきたら、breakでループから抜け出します。
入力がファイルならその終わりは明確です。
しかし、キーボードでは「終わり」などありません。そこで、特別なコードを入力したら「キーボードからの入力の終わり」だと処理することにしています。これがWindowsではCTRL+Z,Unix系ではCTRL+Dです。
文字を表わすのに使われるのはASCIIコード(とその互換コード)だけではありません。例えば、一部大型コンピュータではEBCDICというASCIIとまったく違うものが使われています。当然、そう言うマシンでは、getchar()はASCIIではなく、それぞれのコードを返します。
'0'と書いた方がよく、48と直接書くべきではない理由は、ASCIIコードとは限らないから、ということもあります。
※ 一応、'0'から'9'までが連続していることは規格に保証されているですが。
まあ、こんな練習用コードを他の環境で動かすことも無いし、ASCII以外のコードを使ってる環境なんて、一般人はめったに触れることもないくらいにASCIIが普及しているので、間違いとまではいいきれませんが。
それでも「ASCIIだと理解して使う」のと「ASCIIだと思い込んで使ってしまう」のとでは違うので。
No.3
- 回答日時:
1.まず0~9の文字が入力された回数を覚えておく為の入れ物(配列)cntを用意
2.getchar()で、キーボードからの入力結果をchに代入
3.入力された文字を判定し、カウントアップ
4.結果を出力
という流れになります。
++という演算子は、今の値に1プラスするという意味なので、これでカウントアップできている訳です。
無限にカウントされないのは、無限ループの最初でgetchar()を呼んでるからです。
switch文で判定を行ってカウントアップした後、すぐにgetchar()が呼ばれて、キーボードからの入力待ち状態になるからです。
ちなみに、余計に混乱するかもしれませんけど、余談としてこのプログラムの改善点を書いておきます。
出現回数を配列に入れてますが、最後の結果出力でしかその恩恵を受けていません。
せっかく配列を使用してるので、冗長なswitch文の判定箇所をもっとコンパクトにできます。
swich文の箇所を以下にコードに書き換えても、全く同じに動きます。
int index = ch - '0';
if (index >= 0 && index <= 9)
cnt[index]++;
解りやすいご説明ありがとうございます。
おかげで無限ループに入らない理由もわかることができましたし、改善点も教えて頂いて短くすることもできました。
ただ一つだけまだわからないことがあるのですが、例えば3.14と入力した時、chの値が51→49→52と変化して行くのは何故なのでしょうか、chの値が変化する要因がどの部分なのかが理解できていなくて・・・、getchar関数とは入力した文字を順番に3、.、1、4、と返す関数ということなのでしょうか・・?
No.2
- 回答日時:
>数値を入力した時点で51や49といったそれぞれ違う数値が表示されるのですが
とりあえず、「数値」と「数字」の違いは区別できる様になっておいた方が良いでしょう。
>教科書には「CTRL+Zは入力の終了を意味する」とあるのですが、これは一体どういう意味なのでしょうか、強制的に割り込んでEOFを代入するということなのでしょうか・・・?
Windowsのコマンドプロンプト(古くはDOS)で、「標準入力からEOFを入力する手段」がCTRL+Zとなっているだけです。
環境が変わるとCTRL+Zではなくなる場合もありますので誤解無きよう。
# LinuxのbashだとCTRL+Dですし。
No.1
- 回答日時:
>何故chの値が変更していくのかがわかりません
ch = getchar();
で「chに、getchar()関数からの戻り値を代入している」のは理解していますか?
getchar()関数が「何を返すか?」を理解していますか?
getchar()関数は、キーボード入力に応じて色々な値を返すって事を理解できていますか?
getchar()は「キーボードから入力された文字を返す関数」なのは理解できていますか?
>その後の無限ループからの脱出をCTRL+Zがどうして引き起こすのかも理解できず困っています
if (ch==EOF) break;
のif文が「chがEOFならbreak文によってループを抜ける」ってのは理解できてますか?
getchar()がEOFを返すと、chの値がEOFになるのは理解できてますか?
つまり「getchar()がEOFを返すとループを抜ける」って事なんですが、それは理解できてますか?
>教科書には「CTRL+Zは入力の終了を意味する」とあるのですが、これは一体どういう意味なのでしょうか
「CTRL+Zを入力すると、入力終了状態になり、getchar()がEOFを返す」って意味。
getchar()がEOFを返してきたら、どういう動作になるか、理解できていますか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# 現在プログラムを作っているのですが、実行したときに写真のように結果が表示されるのですが、これを CH 2 2023/01/18 16:22
- C言語・C++・C# C++のcase文の書き方 4 2023/02/24 20:50
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- JavaScript switch文のswitch(n)の部分を複数の値にするか、if文に変えてほしいです。 1 2022/07/27 17:18
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
数字以外が入力されたらエラー...
-
*をユーザーが入力した数字の数...
-
正負を反転させて出力するプロ...
-
プログラミング初心者です。 Py...
-
至急教えてください!プログラ...
-
cout関数を使っているのですが...
-
scanfでの可変引数
-
scanfが2回使えない・・・?;
-
batプログラム上で文字列を入力...
-
プログラミングの問題です 「金...
-
C言語・標準入力でquitを入力で...
-
java初心者です。入力されたの...
-
日数を計算する方法
-
C++:cinが上手く使えない
-
C言語scanf_sで何故か2回入力に...
-
C言語について
-
入力エラーの処理について。
-
scanf が無視されます
-
Linuxで入力待ちなしkeyread関...
-
Eclipseコンソール表示を、リセ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
double型が正常に認識されてい...
-
プログラミング初心者です。 Py...
-
正負を反転させて出力するプロ...
-
Excel VBAで、Application.Inpu...
-
C言語について。
-
batプログラム上で文字列を入力...
-
*をユーザーが入力した数字の数...
-
cout関数を使っているのですが...
-
漢字のソートについて
-
数字以外が入力されたらエラー...
-
Userformの入力順序をタブオー...
-
ワードで文字を入力する時の変...
-
Linuxで入力待ちなしkeyread関...
-
java初心者です。入力されたの...
-
EDITコントロールで入力できる...
-
Eclipseコンソール表示を、リセ...
-
小数か整数かを判定する方法
-
C言語scanf_sで何故か2回入力に...
-
VB.NETで16進数+16進数や16進...
-
Linuxプログラミングで、キーボ...
おすすめ情報