こんにちは、独学でC言語を勉強しているゆみころです。
とある例文(This is a pen. )などを入力し(制限:256字まで Ctl+Zで入力終了)、そのアルファベットの出現頻度求めるプログラムを作っています。
(アウトプットとして A=0回、B=2回、C=1回などでてくるようです)
またもや2日考えましたが、解決が見つからず困っております。
すみませんがどなたかお助け下さいませんか?
よろしくお願いします。
質問(1)
コメントで/*このソースの意味がわからない*/ といる行の説明をお願いできますでしょうか?
質問(2)
エラーで沢山アポストロディーがIllegalだとでてきました。私の使用しているアポストロフィーは使えないのでしょうか?
ノートパッドで作成し、その後Borlandでコンパイルしています。
お礼コメントは絶対します!しかし、On timeにできない場合があります、すみませんがよろしくお願いします。
★ゆみころ★
*********勉強している本からの例をそのままコンパイルしようとしました**************
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#define MAX 256 /*Max input data*/
#define ALPHA 26/*Alpha nubmer a - z*/
void main(void)
{
char str[MAX];
int alpha[ALPHA];
int i;
memset(&alpha[0],'\0',sizeof alpha);/*アルファの0配列からalphaの配列分だけ0で埋めてくれる->0で初期化*/
for(;scanf("%s",&str[0]!=EOF;) /*continue till EOF(Ctl+z) */
{
for(i=0;str[i]!='0';i++)
{
if(isalpha(str[i]))/*アルファベットか?*/
{
str[i]=(char)toupper(str[i]);/*このソースの意味がわからない。Capitalへ conversionできるのは理解できましたが、なぜ(char)がいるのですか?*/
(alpha[str[i]-'A'])++;/*このソースの意味がわからない 該当文字出現回数を更新しているそうです*/
}
}
}
for(i=0;i<ALPHA;i++)/*alphabet 26回分繰り返す*/
{
if((i%5)==0)/*横に5こづずならべる*/
{
putchar('\n');
}
printf(" %c=%5d",i+'A',alpha[i]);
}
putchar('/n');
}
*********エラーメッセージ*************************
C:\Practice>bcc32 alph2.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
alph2.cpp:
Error E2206 alph2.cpp 10: Illegal character ' ' (0x8140) in function main()
Error E2206 alph2.cpp 14: Illegal character '[' (0x816d) in function main()
Error E2121 alph2.cpp 14: Function call missing ) in function main()
Error E2206 alph2.cpp 14: Illegal character ']' (0x816e) in function main()
Error E2034 alph2.cpp 15: Cannot convert 'int' to 'char *' in function main()
Error E2121 alph2.cpp 15: Function call missing ) in function main()
*** 6 errors in Compile ***
No.3ベストアンサー
- 回答日時:
なんか質問者が理解できてないのかTacosanさんの回答を右から左に流しているので,
実際のコードで見せてみます。
// memset も微妙だけど (初期化すればいいのに)
// -> = {0}で宣言時に初期化。
int alpha[ALPHA] = {0};
int c;
// ・なんで scanf を使ってるんだろう. 1文字ずつ読み込むようにすればバッファオーバーランなど起こりようもないのに.
// -> getcharを使ったプログラムに変更。1文字ずつ処理してバッファーに入れるという動作をしないので、バッファオーバーランは起きない。strの代わりにcというint型の変数を使うことにする。
// ・条件式しかない for って, あんまり普通じゃないと思う. while はお嫌い?
// -> 条件だけ取り出して、while文に書き換え
while ((c = getchar()) != EOF) {
if(isalpha(c)) {
c = toupper(c);
alpha[c - 'A']++;
}
}
以下、落穂拾い的に残りのコメントについて解説します。
> #1 への指摘を先にすると, 15行目は「Cannot convert 'int' to 'char *'」だから「EOF が変換できていない」んだと思います. また, 「for()の閉じ括弧がありません」じゃなくて「scanf の呼び出しの閉じ括弧がない」です (おそらくセミコロンのところでエラーになってる).
質問者もこれには気づいているようなので特にコメントをすることはありません。
ただ、getcharに変更して、scanfにはご退場いただいたのでこのエラーはなくなりました。
ちなみに、scanfは初心者向けの本に必ず書いてあるものの、使える場面が限られている上に、扱いが非常に難しいので自分は殆ど使わないです。代わりにfgets、fgetc、freadを使うことが多いです。
> ・そもそもアルファベットがきちんと並んでいるという保証はどこにもない. Windows なら ASCII がベースなので問題ないけど, 一般論としてはアウト.
文字をコンピュータ上でどう表すかというのを文字コードといいますが、文字コードには様々な種類があります。例えば、ASCIIだとAからZまで文字コードが順に並んでいるものの、EBCDICなどそれが保証されていないこともあって、C言語ではどの文字コードを想定するか決まりがありません。
例えば、ASCIIだと'J' - 'I' は1ですが、EBCDICだと、'J' - 'I'は1ではありません。
だから、大文字 - 'A'が26までの範囲に収まることは必ずしも保証されていません。
ただ、Windowsなど一般に普及している環境ではASCIIを採用していることがほとんどなので、大文字 - 'A'が26未満と想定しても問題になることはほぼないでしょう。
あえてやるならこうやって求めるとかでしょうか。
const char alphabet_sample[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int get_index(int c) {
char* p = index(alphabet_sample, c);
if (p != NULL)
return p - alphabet_sample;
else
return -1;
}
もっとマシな書き方はありそうですが。
> ・str[i]!='0'
これは、誤植したんでしょうね。str[i] != '\0'とすべき。
このコードもscanfからgetcharに変更したことでなくなりました。
文字と数値では意味が全然違います。
str[i] != 0だと0という数値との比較ですが、str[i] != '0'だと0という文字との比較になります。
'0'の文字コードはASCIIだと48なので、str[i] != '0'はstr[i] != 48と書いてるのと同じ動作をします。
一方str[i] != '\0'だと'\0'はNULL文字で、数値の0に中身はなっているはずなので、str[i] != 0と同じ動作をします。
ただ、文字として扱っているということを意識すると、str[i] != '\0'が正しいです。
> ・putchar('/n');
これも誤植ですね。
正しくはputchar('\n')でしょう。
以上の修正をして、FreeBSD上でコンパイルして動かしてみるとこんなかんじです。
>./a.out
Hello World!
^D
A= 0 B= 0 C= 0 D= 1 E= 1
F= 0 G= 0 H= 1 I= 0 J= 0
K= 0 L= 3 M= 0 N= 0 O= 2
P= 0 Q= 0 R= 1 S= 0 T= 0
U= 0 V= 0 W= 1 X= 0 Y= 0
Z= 0
>cat /COPYRIGHT | ./a.out
A= 284 B= 93 C= 180 D= 220 E= 556
F= 140 G= 84 H= 157 I= 473 J= 3
K= 18 L= 177 M= 110 N= 351 O= 396
P= 102 Q= 5 R= 359 S= 337 T= 471
U= 142 V= 48 W= 68 X= 13 Y= 82
Z= 1
というわけで、頑張って。
hanabutako先生、
ご親切なご回答をどうもありがとうございました。
実際のコードありがとうございました。
Tacosan先生の言っている意味がわかりました。
たぶん本では memsetという変数を紹介したかったんだと思います。
今までのPageではなく初登場でしたのであえて紹介したんだと思います。
たしかに使い勝手が悪いので 普通の初期化の方がいいと思いました。
この本は全てscanfを使ってます、基礎編だからでしょうか?
getcharはたまにしか出てきません、きっと応用編にいったらgetcharを使うように書いてあるのかもしれません。
whileでも書けるんですね!
見やすいしわかりやすいです!
ありがとうございました。
>>str[i] != '\0'とすべき。
>>正しくはputchar('\n')でしょう。
ご指摘ありがとうございました。
間違っていました。ほんとうに私はよく間違えて気付かないので情けないです。
(何回も見直し考えましたが 気づきませんでした涙)
すべてを直したら無事にプログラムは動き、結果も正しく得られました。
詳しい解説のおかげで 私が理解できなかった1行も理解することができました。
長々とお付き合い頂きhanabutako先生はじめ
皆さま、どうもありがとうございました。
私が理解できていないのは、頭が悪いのと、C言語を学校へ行かず一人で勉強しようと無茶をしていることと
日本語が得意ではないからです。
何度もこちらで親切で物知りな先生たちに助けてもらいただただ感謝です。
すみませんが、今後ともよろしくお願いします。
★ゆみころ★
No.2
- 回答日時:
#1 への指摘を先にすると, 15行目は「Cannot convert 'int' to 'char *'」だから「EOF が変換できていない」んだと思います. また, 「for()の閉じ括弧がありません」じゃなくて「scanf の呼び出しの閉じ括弧がない」です (おそらくセミコロンのところでエラーになってる).
ただ, このプログラムはいろいろと突っ込みどころが....
・なんで scanf を使ってるんだろう. 1文字ずつ読み込むようにすればバッファオーバーランなど起こりようもないのに.
・条件式しかない for って, あんまり普通じゃないと思う. while はお嫌い?
・そもそもアルファベットがきちんと並んでいるという保証はどこにもない. Windows なら ASCII がベースなので問題ないけど, 一般論としてはアウト.
・str[i]!='0'
・putchar('/n');
memset も微妙だけど (初期化すればいいのに)
Tacosan先生、
ご指摘どうもありがとうございました。
scanfのカッコはお陰さまで修正済みです、ありがとうございました。
いろいろ突っ込むところはあると思いますが
私はまだ自分で作れるレベルまで達しておらず、本に書いてあるものをそのまま真似して作って
本当に動くかどうかとなぜそのソースで結果が得られるのかを理解するのが精一杯です。
もっと便利な変数があったり、きれいな書き方もあると思いますがどのように修正していくかも今はわかりません。(今回指摘頂いたこともいずれわかるようになりたいです)
分かる人から見たら 気になって仕方ないと思いますが
どうぞご了承くださいませ。
今後ともご指導をよろしくお願いします。
★ゆみころ★
No.1
- 回答日時:
>str[i]=(char)toupper(str[i]);/*このソースの意味がわからない。
Capitalへ conversionできるのは理解できましたが、なぜ(char)がいるのですか?*/toupper()のマニュアルを見ましょう。
戻り値の型はint型になっているかと。
小さい型への代入になりますので、明示的にキャストしているのでしょう。
>(alpha[str[i]-'A'])++;/*このソースの意味がわからない 該当文字出現回数を更新しているそうです*/
この中のどの部分が不明…なんでしょうか?
str[i]の値は直前の判定で半角アルファベットの大文字であることが確定しています。
つまり'A'から'Z'です。
そこから'A'の文字コードを引いた値はいくつになると思いますか?
>for(;scanf("%s",&str[0]!=EOF;) /*continue till EOF(Ctl+z) */
閉じ括弧が1つ足りないようですが?
また、この方法でも256字以上入力するとバッファオーバーランになります。
http://www.kijineko.co.jp/tech/superstitions/buf …
scanf("%255s",&str[0])
または
scanf("%255s",str)
でしょうかね。
>Error E2206 alph2.cpp 10: Illegal character ' ' (0x8140) in function main()
ソースコードの10行目に全角空白が紛れ込んでいるようです。
「char str[MAX];」の間違いではありませんか?
# charとstr[MAX];の間の空白が全角空白ではありませんか? 多バイト文字は変数名などには使用できないでしょう。
>Error E2206 alph2.cpp 14: Illegal character '[' (0x816d) in function main()
>Error E2121 alph2.cpp 14: Function call missing ) in function main()
>Error E2206 alph2.cpp 14: Illegal character ']' (0x816e) in function main()
&alpha[0]の括弧が全角になっていませんか?
>Error E2034 alph2.cpp 15: Cannot convert 'int' to 'char *' in function main()
>Error E2121 alph2.cpp 15: Function call missing ) in function main()
scanf()の閉じ括弧が無い為、第2引数が「&str[0]!=EOF」になっています。
&str[0]がchar *で、EOFとの比較の為にint型に変換できていません。(「Cannot convert~」のエラー)
で、for()の閉じ括弧がありません。(「Function call missing )~」のエラー)
Wr5先生、
今回もご丁寧なご回答どうもありがとうございました。
(char)toupperについてキャストの概念を忘れていました。
理解できました、ありがとうございます。
>(alpha[str[i]-'A'])++;/*このソースの意味がわからない 該当文字出現回数を更新しているそうです*/
この中のどの部分が不明…なんでしょうか?
str[i]の値は直前の判定で半角アルファベットの大文字であることが確定しています。
つまり'A'から'Z'です。
そこから'A'の文字コードを引いた値はいくつになると思いますか?
→同じ解説が本にも書いてありましたがまだ私には理解ができません。
前ラインで入力した文字を全て大文字変換しそれをstr[i]へ格収したのは理解できましたがなぜこの一行で出現回数を更新できるのかが謎です。
馬鹿ですみません。
>for(;scanf("%s",&str[0]!=EOF;) /*continue till EOF(Ctl+z) */
→カッコが足りない件のご指摘どうもありがとうございました。
エラーが消えました。
バッファオーバーランのAdditional Inforありがとうございました。
私にはまだ難しくて理解できませんが、わかるようになったら参考にさせて頂きます。
空白や全角ミスのご指摘ありがとうございました。
全てなおし、無事コンパイルはできました。
しかし、実行しても結果がでてきません。涙
まだ何か間違っているのでしょうか?
よろしくお願いします。
★ゆみころ★
*******修正後*********
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#define MAX 256 /*Max input data*/
#define ALPHA 26/*Alpha nubmer a - z*/
void main(void)
{
char str[MAX];
int alpha[ALPHA];
int i;
memset(&alpha[0],'\0',sizeof alpha);/*アルファの0配列からalphaの配列分だけ0で埋めてくれる->0で初期化*/
for(;scanf("%s",&str[0])!=EOF;) /*continue till EOF(Ctl+z) */
{
for(i=0;str[i]!='0';i++)
{
if(isalpha(str[i]))/*アルファベットか?*/
{
str[i]=(char)toupper(str[i]);/*Capital conversion*/
(alpha[str[i]-'A'])++;/*該当文字出現回数を更新*/
}
}
}
for(i=0;i<ALPHA;i++)/*alphabet 26回分繰り返す*/
{
if((i%5)==0)/*横に5こづずならべる*/
{
putchar('\n');
}
printf(" %c=%5d",i+'A',alpha[i]);
}
putchar('/n');
}
*********実行結果***************
C:\Practice>alph2
this is a pen. ^Z
C:\Practice>
何もでてきませんでした涙
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
c#でbmp画像の上下反転
-
「ポインタのポインタ」を使っ...
-
C言語について。
-
int main()の・・・
-
テキストデータをそのままバイ...
-
char型からのバイト数取得
-
Linuxでフォルダ内全ファイル名...
-
coutにchar型の変数を使ったら...
-
sprintf関数の作り方
-
絶対パスからのファイル名の切...
-
strncpyと_tcsncpy_sのヌルの扱...
-
main の引数には const 付けた方が
-
ftoa の作り方
-
C言語のポインターで詰まっている
-
'const char *' 型は 'char *' ...
-
文字列がNULLか空文字列かの判定
-
CStringをwchar_tに変換したい
-
SMTP-AUTH 334
-
【C言語】文字型と整数型の違い
-
fgetsなどのときのstdinのバッ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
charでの計算?
-
文字列から空白を取り除きたい...
-
CStringをwchar_tに変換したい
-
C言語のfor文です。 繰り返しの...
-
charからLPTSTRへの変換方法
-
fgetsなどのときのstdinのバッ...
-
'const char *' 型は 'char *' ...
-
間接参照のレベルが異なっています
-
double型の値をchar配列に変換...
-
atoi( ) の反対をやりたい
-
間接操作のレベルとは
-
ネットワークにつながっている...
-
型変換
-
テキストデータをそのままバイ...
-
文字列ポインタを結合
-
3桁区切(コンマ)記号をつけ...
-
C言語です
-
Win32APIでのエディットボック...
-
TCHAR文字列?の特定部分の数字...
-
絶対パスからのファイル名の切...
おすすめ情報