• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C言語の質問です。)

C言語のデータ処理方法についての質問

このQ&Aのポイント
  • C言語で整数データを処理する方法について質問です。具体的には、一万個以上の整数データを読み込んで個数を出すプログラムを作りたいのですが、どのように記述すれば良いかわかりません。配列の使用方法にも苦手意識があります。アドバイスをいただけると助かります。
  • C言語で一万個以上の整数データを処理するプログラムを作成したいです。個数を出力するために、データをすべて読み込み、同じ整数がいくつあるかをカウントする必要があります。しかし、配列の使用方法が苦手であり、どのように記述すれば良いかわかりません。アドバイスをお願いします。
  • C言語で一万個以上の整数データを処理するプログラムを作成していますが、行き詰まっています。データをすべて読み込んで同じ整数がいくつあるかをカウントする必要がありますが、配列の使用方法がよくわかりません。具体的には、整数データを格納する配列のサイズをどのように指定すれば良いかわかりません。アドバイスをいただけると助かります。

質問者が選んだベストアンサー

  • ベストアンサー
  • neko1963
  • ベストアンサー率49% (127/258)
回答No.4

こんな感じでいかがでしょうか? #include <stdio.h> #include <process.h> int main(void) { FILE *fp; int n, old_n, cnt; fp=fopen("test.dat","r"); if(fp==NULL) { printf("file open error!!\n"); exit(1); } cnt = 0; old_n = 0; while(fscanf(fp, "%d\n", &n)!=EOF){ if(n > old_n) { /* 次の数字が出現した */ printf("%d = %d\n", old_n ,cnt); old_n = n; cnt = 1; } else { /* 入力データは昇順にソート済みという前提 */ /* 同じ数字が続いた n == old_n の場合 */ cnt++; } } /* 最後の数字の出現回数を出力 */ printf("%d = %d\n", old_n ,cnt); fclose(fp); return 0; } [入力データサンプル] 0 0 1 2 2 3 4 5 5 5 8 8 10 10 11 11 11 12 12 12 12 100 100 100 110 110 110 110 110 1000 1000 1200 1200 1200 1200 1200 1200 7000 7000 7000 7000 7000 7000 7000 7000 7000 7000 8700 8700 8700 [実行結果] 0 = 2 1 = 1 2 = 2 3 = 1 4 = 1 5 = 3 8 = 2 10 = 2 11 = 3 12 = 4 100 = 3 110 = 5 1000 = 2 1200 = 6 7000 = 10 8700 = 3

rikerume01
質問者

補足

ありがとうございます。 #include <process.h>とはどういったものなのでしょうか?

その他の回答 (12)

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.13

なぜ固定配列を使いたいのか、課題か何かでしょうか。 固定でないもの(ファイルの中の要素)を、固定配列で 表現することは、普通に考えて無理がある。 動的なメモリ確保(Cならmalloc、C++ならnew)を使いましょう。 C++を使っていいなら、std::mapなどを使えば、ファイルから 読み取りながら連想配列に値をどんどん格納することができます。 固定配列の勉強のためなら、制約条件(要素数上限を決める。例えば10000とか) を付けて、その条件下で動作するプログラムを書くことはできますが、 固定配列を使うことは稀で、動的配列を使う勉強をしておいた方が、役に立ちます。 要素が「数」ではなく単語などの「文字列」になったときのことも考えたり しなくて良いのか、なども実装方法を検討する材料の1つです。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.12

って~か, Linux なら uniq -c 入力ファイル | sed -e 's/\\(\\d\\d*\\).*/\\1/' | sort | uniq -c のような感じでいいんだよね.... #2 にも書いたように, uniq/sed/sort を組合せるだけ, わざわざプログラムを作るまでもない.

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.11

既に解決したようですが、(2)の結果を中間ファイルで(3)に渡す例を御参考までに書き込んでおきます。 ■(1)~(2) の処理プログラム例 int main(void) { FILE *fp; FILE *fp_tmp; int n, old_n, cnt, max_cnt; fp=fopen("FILENAME","r"); if(fp==NULL) { printf("file open error!!\n"); exit(1); } fp_tmp = fopen("temp.dat","w"); if(fp_tmp==NULL) { printf("temp1 file open(w) error!!\n"); exit(1); } /*--- 読み込んだ整数のそれぞれの出現回数をカウントする--- */ cnt = max_cnt = 0; old_n = 0; while(fscanf(fp, "%d", &n)!=EOF){ if(n > old_n) { /* 次の数字が出現した */ /* 中間ファイルのレコード上は "出現回数 数字" という順番 */ fprintf(fp_tmp, "%10d %10d\n", cnt, old_n); if(cnt> max_cnt) max_cnt = cnt; old_n = n; cnt = 1; } else { /* 入力データは昇順にソート済みという前提 */ /* 同じ数字が続いた n == old_n の場合 */ cnt++; } } /* 最後の数字の出現回数を出力         */ /*    諸元値として10桁(MAX 99億・・・)を想定 */ fprintf(fp_tmp, "%10d %10d\n", cnt, old_n); fclose(fp); fclose(fp_tmp); return 0; } ■[入力データ(例)] 0 0 1 2 2 3 4 5 5 5 8 8 10 10 11 11 11 12 12 12 12 100 100 100 110 110 110 110 110 1000 1000 1200 1200 1200 1200 1200 1200 7000 7000 7000 7000 7000 7000 7000 7000 7000 7000 8700 8700 8700 ■[中間ファイル]※(2)の出力 2 0 1 1 2 2 1 3 1 4 3 5 2 8 2 10 3 11 4 12 3 100 5 110 2 1000 6 1200 10 7000 3 8700 ※(2)と(3)の間でソート処理が必要です。 ■[中間ファイル]※(2)の出力をコマンドでソートした結果 1 1 1 3 1 4 2 0 2 2 2 8 2 10 2 1000 3 5 3 11 3 100 3 8700 4 12 5 110 6 1200 10 7000 ■(3)の処理プログラム int main(void) { FILE *fp_tmp; int n, cnt, cnt_old, kosuu; fp_tmp = fopen("temp2.dat","r"); if(fp_tmp==NULL) { printf("temp file open(r) error!!\n"); exit(1); } /* temp2.dat は出現回数でソート済み という前提 */ kosuu = 0; cnt_old = 1; while(fscanf(fp_tmp, "%d %d", &cnt, &n)!=EOF){ /* 出現回数が異なる数字が出現 */ if(cnt > cnt_old ) { printf("出現回数が %d回の数字=%d個\n", cnt_old, kosuu); cnt_old = cnt; kosuu = 1; } else { /* 出現回数が同じ数字の個数をカウント */ kosuu++; } } printf("出現回数が %d回の数字=%d個\n", cnt_old, kosuu); fclose(fp_tmp); } ■(3)の出力 出現回数が 1回の数字=3個 出現回数が 2回の数字=5個 出現回数が 3回の数字=4個 出現回数が 4回の数字=1個 出現回数が 5回の数字=1個 出現回数が 6回の数字=1個 出現回数が 10回の数字=1個

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.10

Linuxで(2)までの結果をファイルにリダイレクトして、このファイルを入力して次のプログラムで(3)を行ったわけですか? ANo.8 の「中間ファイル」はリダイレクトでは無いですが、(2)の結果をファイルで(3)に渡す意図は同じです。 なんとか解決されたようで、お疲れ様でした。

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.9

細かい点で1つ忘れていましたが while(fsacanf(fp, "%d\n", &n)!=EOF){ の \n は不要だと思います。 while(fsacanf(fp, "%d", &n)!=EOF){ ※\n あっても影響が出ないかも知れませんが・・・。

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.8

ANo.5の補足の件ですが、もうひとつありました > int ,n,count[10],i; の int count[10] では count[0] ~ count[9] が使えますが、 count[10] は使えませんので実行時にエラーになります (配列範囲外) また、「(2) 読み込んだ整数のそれぞれのすべての個数を出す。」までの処理に限定すれば、ANo.4 が簡潔だと思います。 「(2) 読み込んだ整数のそれぞれのすべての個数を出す。」までの処理結果を中間ファイルに出力して、この中間ファイルを読み込んで「(3) 出した個数の数を数えて出力。」の処理をするのはまずいでしょうか? 中間ファイルを介すれば「(2) 読み込んだ整数のそれぞれのすべての個数を出す。」までの処理結果がファイルとして確保でき「(3) 出した個数の数を数えて出力。」を独立して別のプログラムとして作成できますし、配列サイズ/箱の数に悩む必要もありませんが・・・。

rikerume01
質問者

補足

ありがとうございます。 出きるようになりました。 知識不足で申し訳ないのですが、中間ファイルに保存という方法は使っていません。 というよりは、頭が混乱しないようにまず (2) 読み込んだ整数のそれぞれのすべての個数を出す。のプログラムを実効。 出力結果をLINUXコマンドで手動で保存 3) 出した個数の数を数えて出力。のプログラムを実効。 出力結果をLINUXコマンドで手動で保存 とう流れにあえてしました。 プログラムになれていればより簡単にというのを意識するのですが、自分は本当に苦手なので余計なことを考えずにやろうと思ってしました。

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.7

ANo.5の補足の件ですが  if(n=1) や else if(n=2) などの条件式は if(n==1) や else if(n==2) ではないでしょうか。

rikerume01
質問者

補足

>> if(n=1) や else if(n=2) などの条件式は if(n==1) や else if(n==2) ではないでしょうか 変えてみましたが実効すると動かないで止まったままになってしまいます。

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.6

No.4の #include <process.h>; は、私が使っている処理系では exit を使うために必要でしたので、そのまま記載してあります。 ※正確には ヘッダは <process.h> または <stdlib.h> が必要なのですが。 1本のプログラムに御要望の全機能を記述すると複雑ですので、プログラムを3つぐらいに分けた方が簡潔になるような気がします。 配列を使うのであれば、プログラムで充分足りると思われる数(100,000ぐらい?)を諸元値として決めたほうが考えやすいでしょうね。 ※現時点では、どのぐらいで充分かが不明確だと思いますが、設定した諸元値で足りなかった場合は、あとで見直して変更することはできると思います。

  • neko1963
  • ベストアンサー率49% (127/258)
回答No.5

失礼しました。 No.4は 「(2) 読み込んだ整数のそれぞれのすべての個数を出す。」までのものをペーストしていました。 出現回数を保持するのは、配列あるいは中間ファイルを使って良いと思いますが、配列が良いですか?

rikerume01
質問者

補足

(4)のところを書いてみたのですが。。。配列がよくわからないので なぜか実効すると動かなくなります。 #include<stdio.h> int main(void) { FILE *fp; int ,n,count[10],i; fp=fopen("FILENAME","r"); if(fp==NULL) { printf("file open error!!\n"); exit(1); } for(i=1;i<=10;i++) count[i]=0; while(fscanf(fp,"%d\n",&n)!=EOF) { if(n=1) { count[1]++; } else if(n=2) { count[2]++; } else if(n=3) { count[3]++; } else if(n=4) { count[4]++; } else if(n=5) { count[5]++; } else if(n=6) { count[6]++; } else if(n=7) { count[7]++; } else if(n=8) { count[8]++; } else if(n=9) { count[9]++; } else if(n=10) { count[10]++; } } for(i=1;i<=10;i++) printf("%d %d\n",i,count[i]); fclose(fp); return 0; } どこがまずいんでしょうか? よろしくお願いまします。

  • TT414
  • ベストアンサー率18% (72/384)
回答No.3

(1)ファイルを読んでみて数字の最小値と最大値を求める。 (2)最大値-最小値+1のメモリを確保する。 (3)ファイルを読み直し各数値ごとの頻度を求める。 (4)頻度の表示。 (2)の時大量すぎてメモリが獲得できないときは最小値と最大値を分割して(3)を繰り返し、最後に(4)をすれば大丈夫です。

関連するQ&A