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

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

新規登録して質問してみよう
ただいま回答率
85.38%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

Q&A

解決済

2回答

719閲覧

ファイル入出力で各文字の文字数をカウントするプログラムの作り方を教えてください(質問初めてです)

KAKAKASASASA

総合スコア1

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

0グッド

0クリップ

投稿2023/09/09 11:52

編集2023/09/11 07:54

入力されたファイルに書かれている各文字をカウントする

例えば 
Oh say can you see, by the dawn's early light,
という文字列が入力ファイルに書かれている場合下のように
O: 1
a: 4
b: 1
d: 1
e: 3
h: 3
i: 1
l: 2
といった具合に出力ファイルに書き込みたいんです。
ですが、やり方が全く分からず何とか思いついたコードを書き込んでも、正解にかすりもしないので助けて下さい。
まだまだ初心者なので、できるなら解決策だけでなく、足りない知識や考え方を教えてください。
使っているソフトはMicrosoft Visual studioで、言語はC言語です

発生している問題

下にある自分が作ったコードでは、なぜか最初の一文字だけをカウントし出力し終了してしまう事と、なぜか入力ファイルが真っさらになっている事。
エラーメッセージはありましたが、色々やっていたらなぜかいつのまに消えていました。(怖い)

該当の自作ソースコード(一部修正済み)

#include <stdio.h> #include <stdlib.h> int main(void){ int i ,count, str[100] = { 0 },c; FILE* fp; FILE* fpout; if ((fp = fopen("13-3in.txt", "r")) == NULL) { printf("error message"); exit(1); } if ((fpout = fopen("13-3out.txt", "w")) == NULL) { printf("error message"); exit(1); } while ((c = fgetc(fp)) != EOF) { count = 0; for (i=0; i <= 100; i++) { else if (c == '!' + i) { str[i]++; } } } for (i = 0; i < 100; i++) { if (str[i] >= 1) { fprintf(fpout, "%c; %d\n", ('!' + i), str[i]); } } fclose(fp); fclose(fpout); return 0; }

試したこと

手探りなので、全く試す方法などがわかりません。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

  1. まずはファイルは読み込むだけにして、ループで1文字ずつ標準出力に出す
  2. ループで文字ごとにカウントして、結果を標準出力に出す
  3. 結果を別のファイルに出す
  4. 結果を元のファイルに追記する

くらい段階を踏んでいっても良いのではないかなと。


肝心のカウントの箇所ですが、
せっかく str[100] というバケツを用意して(ちゃんと0初期化もして)いるので
「同じ文字が登場したら、バケツ内の同じ場所でカウントしている」前提を意識して
もっとシンプルに「ループ処理の1文字に対して、バケツの1か所を1だけカウントアップしていく」というロジックでいいいはずです。

あと、'!' が登場しているのは、どこかのアルゴリズム解説ページを参考にしたのでしょうか?
カウント時のスペース除外とか制御文字とかを意識したのかもしれませんが、段階を踏むということで

  1. まずは何も考えずに全部カウントする
  2. シンプルにカウントできるようになったら、文字種も意識してみる

がよいかなと。


もし↑のバケツという考え方もピンとこないのであれば、完全に割り切って

  1. まずは 'a' という固定の1文字だけをカウントしてみて、何回出てきたか標準出力に出す
  2. 次は、 'a' と 'b' の2文字をそれぞれカウントしてみる
  3. ...
  4. じゃあ、全てのアルファベットや記号を漏れなくカウントするには?
  5. (今回は不要かもしれないけど) ひらがなカタカナ漢字も含めて、登場した文字を全部カウントするには?

ともっと細かい段階を踏んでいきましょう

投稿2023/09/09 15:25

pecmm

総合スコア624

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KAKAKASASASA

2023/09/10 09:23 編集

分かりました。いきなり一気に色んな処理を詰め込むのではなく、少しずつ細かく段階を分けてコードを書いてみます! ’!’は自分で考えました。’!’から’~’までの文字をカウントしたいため書きました。
guest

0

ベストアンサー

なぜか入力ファイルが真っさらになっている事。

については、入力ファイル名と出力ファイル名が同じだからです。
fopen("13-3in.txt", "w")を実行した時点で、ファイル 13-3in.txt の中味は空になりますので、
読むと最初からEOFです。

プログラム部分では、1文字ずつ処理するwhileループの中の、ijcountがそれぞれ何の目的を持った変数なのかが理解できません。なので、ゼロから正しいプログラムを書いて示すことは簡単ですが、元のプログラムの意図に沿った形で修正することが出来ません。
特に、ijはどちらかが、文字!から~まで調べたい文字を順番に意味する数値なのでしょうが、何故似たような物が2つあり、何故ループが2重なのかがさっぱりです。

おそらく自分でも書いている内に分からなくなってしまっているのだと思います。
プログラムを書く前に、変数名とその意味を表に書き出して、常にそれを見ながらコーディングすると良いです。
i: ループカウンター」とかじゃなくて具体的に詳しく。
まず日本語で全体の処理手順を書いてみるとかも有効です。

追記

元のプログラムの方針で完成したようなので、別解を書いておきます。変数名はそのままにしてますが。

C

1(前略) 2int str[256] = {0}; 3(中略) 4while ((c = fgetc(fp)) != EOF) 5{ 6 str[c&255]++; 7} 8for (i = '!'; i <= '~' ; i++) { 9 if (str[i] >= 1) { 10 fprintf(fpout, "%c; %d\n", i, str[i]); 11 } 12} 13(後略)

別案:

C

1(前略) 2int str['~'-'!'+1] = {0}; // str[94]と書いても良いが 3(中略) 4while ((c = fgetc(fp)) != EOF) 5{ 6 if(c>='!' && c<='~') { 7 str[c-'!']++; 8 } 9} 10for (i = '!'; i <= '~' ; i++) { 11 if (str[i-'!'] >= 1) { 12 fprintf(fpout, "%c; %d\n", i, str[i-'!']); 13 } 14} 15(後略)

投稿2023/09/09 12:47

編集2023/09/11 11:02
otn

総合スコア85684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KAKAKASASASA

2023/09/10 07:45

なるほど、ファイルが真っ白になる原因がわかりました。ありがとうございます。 すいません。jとそのループはまったく意味がありませんでした。 具体的に(少し下手な)日本語で書くとまずwhile文で13-3in.txtから文字を1文字ずつ入力?し、次のfor文で入力された1文字が!から~までのどの文字か認識?します。’!’+iというのは例えば入力された文字が'!'だったらiは0なので、str[0]に'!'文字数プラス1カウントする。また'a'だったら'!'+iでiは64なのでstr[64]に文字数プラス1カウントする。といった具合です。 for文が終わったらwhile文に戻り、13-3in.txtから2文字目を取得して、for文でどの文字か判別しその文字の配列の場所に+1してまた3文字目とEOFまで読み込むといった風に処理したいんです。そして結果でstr[0]つまり'!'のカウント数(中のデータ)を出力ファイル?に書き込みたいんです。 しかし、それができずなぜか1文字目を1カウントしたまま終了してしまいなぜ「while ((c = fgetc(fp)) != EOF)」がそのまま2文字目以降入力?してくれないのかが分からないんです。 どうすればこの問題を解決できるのでしょうか?
otn

2023/09/10 15:17

今時点の変更後のコードを実行してみましたが、ちゃんと正しい結果が出ましたよ。 古いコードを実行したのでは? とりあえず、おかきのコードで期待通り動作はすると思います。 おかしいというか間違っているのは、countですね。 日本語で書いたつもりの部分に出てこない。日本語で考えたことに沿ってコードを書いてないと言うことでしょう。 「日本語で書いてみたら?」というのはcountの意味について考えて欲しかったのですが。 お書きのコードでcountの使われ方としては、 ・1文字読んだ後で0を代入 ・読んだ文字が対象ならプラス1、つまり1が代入された状態になる ・配列の該当要素に、count つまり 1 を加算 ⇒ 加算される時点では常に1なので変数の存在価値がなく、str[i]++; でOK。
KAKAKASASASA

2023/09/11 07:53

str[i]++でも1を加算できるんですね、今知りました。ありがとうございます。 それと問題の件ですが、古い間違ったコードのまま実行していました。現在のコードが正しいです。お騒がせしてすみません。 もっと冷静に考えればわかる事なのに、わざわざ質問して時間を掛けてしまいすみませんでした。 これからはもっと論理的に順序良く考えるよう頑張ります。 感謝の言葉 分かりやすく成長を促す助言をしてくれたpecmmさん、問題解決まで親切に分かりやすく教えてくれたotnさん のお二人のおかげで解決できました。ありがとうございます。特にotnさんのおかげです。ありがとうございました。
otn

2023/09/11 10:57

> str[i]++でも1を加算できるんですね、今知りました。ありがとうございます。 自分で「for (i=0; i <= 100; i++) 」と書いてるのに?? > 古い間違ったコードのまま実行していました。現在のコードが正しいです。 作業ミス、タイプミスなど手作業にミスは必ずあるので、中上級者だとミスが起こりにくい手順を行い、ミスが起こりえる手順の場合はミスが無いかを確認します。このサイトで見ていると、初心者は、自分が作業ミスやタイプミスをすることが「想定外」の人が多いですね。経験を積めば「手作業にミスは必ずある」という前提で行動出来るようになるかと思います(基本は自動化)。 別の処理方法を追記しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.38%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問