大学で研究のため,プログラミングをしている者です.
現在、外部CSVに実験記録名(SECTION)を記述し,それを読み込んでINIファイルからデータのパラメータ(KEY)を呼び出してに実験システムを動作させています.
プログラムは以下のような構成になっています.都合上、省略してます.
-------------------------------------------------------------------------
// 変数や構造体の宣言
typedef struct Parameter{
int a;
double b;
...
// パラメータが続きます
} Parameter;
Parameter data_value[DATA]; //実験に使用したパラメータの構造体
char data_name[MAX_PATH]; //実験記録名
#define DATA データ数
// 読み出し部
for( int i<0; i<DATA; i++ ){
fscanf( fp, "%s", &data_name ); // EOFを用いたエラーチェックを省略
data_value[i] = getParameter( data_name ); // セクション名を渡して、実験パラメータ構造体を返す関数
}
-------------------------------------------------------------------------
CSVファイルは以下のように実験記録日と時間が記述されたものになります。
-------------------------------------------------------------------------
2012/09/02_10:10:10
2012/09/09_14:10:10
.....
-------------------------------------------------------------------------
INIファイルは以下のように実験記録日と時間をセクション、そのときのパラメータをキーとしたものです.
-------------------------------------------------------------------------
[2012/09/02_10:10:10]
a = 100
b = 61.2
....
[2012/09/09_14:10:10]
.....
-------------------------------------------------------------------------
ただ、この手法だと実験記録をINIファイルとCSVファイルに増やしていくたび(プログラムで処理)に、DATAを変更する必要があり、面倒です。(ちにみにいい結果が得られたときのみ記録するソフトになってます。)
私としては、定数DATAを使わず、CSVファイルから行数を取得したいと思ってます。
そして、パラメータは
Parameter *param = new Parameter[;取得した行数];
のように動的に確保してINIファイルからデータを読み出したいと思ってます.
そこで、あらかじめCSVファイルの行数を取得して、for文の最大値や動的なparamの生成をしたのですが、良い方法はないでしょうか?
友人からは、scanfを2回使って、1回目で行数獲得、獲得した値に基づき動的生成、2回目で実験記録名の読み取りをすればいいといわれたのですが、プログラムとして不細工な気がします。
この手法以外で提案がありましたら、教えていただきたいです。
質問文が長くなってしまい、申し訳ございません.
ご回答よろしくお願い致します.
No.6
- 回答日時:
---------------------------------------------------
vector<Parameter> data_value;
while(fscanf(fp,"%s",&data_name)!=EOF){
data_value.push_back(getParameter( data_name ));
}
---------------------------------------------------
はい。C++だとこういう記述のほうがいいと思います。
既にお分かりだと思いますが、DATAと書いているところの代わりにdata_value.size()を使います。
#5さんのおっしゃるような形で効率を求めるなら、vectorを使う場合はcapacityで予め使いそうな容量を宣言するという手がありますね。
STL全面禁止というコーディング規約も世の中にはあると聞きますが、ことメモリーの管理についてはvectorやstring、smart pointerを使ったほうが圧倒的に不具合が減るのでこういうところはどんどん使うべきだと思います。
No.5
- 回答日時:
reallocで確保サイズを変更していくのが無難という話に違いはありませんが
今回のケースだと、CSVの形式が決まっているようなのでファイルサイズから割り算である程度のサイズは確保できるのでそんな方法も検討してみるとよいのではないでしょうか。
たとえば、
例に挙がっている物だと、1レコードのバイト数は20バイト+改行コードです。
数値の部分が1桁の場合を考慮して、LF改行だと仮定すると最小レコード長は15バイト。
ということで必要な配列数の期待値は ファイルサイズ/15 個ですね。
ファイルサイズは stat() 関数とstat.st_sizeで取得できます。
# ほんとは オープンしたfp からfdを取得してfstatするのがいい。
reallocは、使い方を覚えて損のない関数ですけど、処理の効率を求めるのならば
定数的な計算量になる方法を考えてみるとよいと思います。
あと、reallocはあとで確保領域を縮小する感じで使った方がよいかもしれません。
フラグメント化しないように工夫はされているようですが細かく確保を繰り返すと
あまり効率はよくないです。
No.4ベストアンサー
- 回答日時:
newはC言語に無いですが、同じ事をしたいなら
Parameter *param = calloc(取得した行数, sizeof(Parameter));
ですね。
newというのをC++のつもりで言っているなら、やりたいことを考えるとnewで一括で確保するより、STLのvectorを使ったほうがいいですね。以下、C言語のほうメインで書きます。
> そこで、あらかじめCSVファイルの行数を取得して、for文の最大値や動的なparamの生成をしたのですが、良い方法はないでしょうか?
「"あらかじめ"CSVファイルの行数を取得する」ということをするには、CSVファイルの行数を何らかの方法で数えなくてはなりません。
改行というのはファイルの中に改行を示す文字を入れているだけなので、改行の回数を数えるためには、一度ファイルすべてを読まなくてはなりません。つまり、ご友人の仰る通り行数を調べるためのファイル読み込み、データを入れるためのファイル読み込みの2回のファイル読み込みが必要になります。
実装方針を変えると、1回でも可能になります。
「CSVファイルから実験記録を読みながら不足していたらデータを保存する容量を増やしていく」という方針です。
この場合、配列を使う実装とリストを使う実装の2種類の実装方針があると思います。配列の添字でデータを参照することが多い場合は配列、任意の箇所への挿入や削除が頻繁に行われる場合はリストを使うというのは常識ですが、今回の場合、前者だと予測するので配列での実装になります。もし、リストを使うほうが適切な場合はqueue.hを使うと楽に実装できます。といっても、添字でアクセスしているところはすべてリストを所定の回数たぐるという操作に書きなおしですが。
(参考: http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~ …
http://www.jp.freebsd.org/cgi/mroff.cgi?sect=3&s …
ファイルを読みながらデータを保存する容量を増やし、配列を使う場合、プログラムはこんなかんじになるでしょう。(コンパイルしてみてないのでコンパイルできるかすら保証しませんが)
Parameter *data_value = NULL; //実験に使用したパラメータの構造体
size_t num_data_value = 0, max_data_value = 0;
#define INCREASE_DATA_VALUE_SIZE 1024
char data_name[MAX_PATH]; //実験記録名
// 読み出し部
for (; !feof(fp); num_data_value++){
if (num_data_value >= max_data_value) { // data_valueの容量がなくなったら拡張
max_data_value += INCREASE_DATA_VALUE_SIZE;
data_value = realloc(data_value, max_data_value * sizeof(data_value[0]));
if (data_value == NULL) {
fprintf(stderr, "Error: cannot allocate memory.");
exit(EXIT_FAILURE);
}
}
fscanf( fp, "%s", &data_name );
data_value[num_data_value] = getParameter( data_name ); // セクション名を渡して、実験パラメータ構造体を返す関数
}
以降はnum_data_valueをDATAの代わりに使います。
data_valueを関数で渡すときにはnum_data_valueも一緒に渡すことになります。
普通はdata_value、num_data_value、max_data_valueの3つ組みで構造体を作るかもしれません。
しかしながら、C言語でプログラムを書くには色々とおまじないが多いですし、メモリー周りの問題も簡単に起こせてしまうので個人的にはデータの集計にはPerl Python Rubyなどを使うほうがおすすめでです。今時、PCの性能は昔よりもずっと上がっていますし、スクリプト言語にもJITが実装されているのでファイルI/Oバリバリなことでもさせない限り、そう遅くないですしね。とは言っても、過去の先輩が残していった大量のライブラリーがあったりするとおいそれとスクリプト言語に行く事もできないと思いますが。その場合も、C++を使うことにして、Standard Template Library (STL)を使うと多少は楽になるかもしれません。例えばvectorを使えば何も考えずにメモリーの動的確保から容量の管理、自動的に追加をやってもらえますし、vectorは配列として取り出せますから。
というわけで、C言語で書く場合は不足するたびにreallocでメモリーを確保したら良いと思います。でも、データの集計にはスクリプト言語を使ったほうが楽です。過去の資産がある場合、実はC++を使って、extern "C"でそれを呼び出すようにして、残りはSTLを使うと多少は楽かもしれません。
この回答への補足
ご回答ありがとうございます.
丁寧な回答で、とても勉強になりました.
ちなみに使用している言語はC++で,質問タイトルは間違ってます.すみませんでした.
C++の場合ですとvectorを用いた以下のような記述がベターになるでしょうか?
---------------------------------------------------
vector<Parameter> data_value; // 動的配列
while(fscanf(fp,"%s",&data_name)!=EOF){
data_value.push_back(getParameter( data_name ));
}
---------------------------------------------------
No.3
- 回答日時:
C言語がまるで,動的に配列が確保できないかのような回答もあるので
一応言っておくと,参考URLのようにできるので,
EOFにならない限り,動的に構造体のメモリ領域を生成していけば良いのでは.
参考URL:http://itpro.nikkeibp.co.jp/article/COLUMN/20061 …
No.2
- 回答日時:
動的に配列を確保できるプログラミング言語があるのですが、それはもう少し複雑な処理をしているようですが、基本的にはNo.1で書かれているようにlist構造を使っているようです。
プログラムの簡単さからいうと、質問者さんが書かれているように最初に行数を数えて、配列要素を確保してからの方が良いように思います。
余談ですが
データ処理をするためにプログラムを自作することがよく有るのですが、普段はRubyを使っています。先に書いたように動的に配列を確保できる言語です。配列の要素数を宣言する必要がありませんので、ともかくデータを読みつつ、状況に応じて配列要素を追加していく方法が簡単にとれます。
いろいろデータを突っ込んだ「配列」をそのまま処理してもいいし、処理速度を考慮してCやFORTRAN型の配列に変換してから計算することもできます。この前簡単なプログラムでCと比べてみたのですが、全体の計算速度が1/10程度に遅くなるだけで、十分な速度が得られています。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) データ解析ソフトRでのファイル入力read.csvがエラーになります 7 2022/03/27 22:11
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- システム CSVファイルのマッピング処理の省力化 1 2022/11/24 00:01
- PHP htmlspecialcharsが機能していないです。 バグですか? 1 2022/04/05 01:22
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Excel(エクセル) 【困っています】VBA 追加処理の記述を教えてください。 1 2022/08/25 22:54
- Visual Basic(VBA) VBAで特定の場所にあるCSVファイル(複数)から特定場所を抜き出してExcelに転記したいです。 11 2023/05/23 16:29
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
このQ&Aを見た人はこんなQ&Aも見ています
-
プロが教える店舗&オフィスのセキュリティ対策術
中・小規模の店舗やオフィスのセキュリティセキュリティ対策について、プロにどう対策すべきか 何を注意すべきかを教えていただきました!
-
テキストファイルの行数を取得する方法(C言語
C言語・C++・C#
-
char*を初期化したいのですが
C言語・C++・C#
-
ファイル内のデータを1行削除する方法
C言語・C++・C#
-
-
4
適切な変換関数が存在しない???
C言語・C++・C#
-
5
CSVファイルの特定行の削除
Visual Basic(VBA)
-
6
ボタンの配置を変更したい
C言語・C++・C#
-
7
GetPrivateProfileStringでiniファイル読込む処理を詳しく知りたいのですが・・・
C言語・C++・C#
-
8
数字の入った配列をファイルへ出力。
C言語・C++・C#
-
9
カンマ区切りのデータを配列に読み込みたい
C言語・C++・C#
-
10
外部依存関係について
C言語・C++・C#
-
11
VC++から引数付きexeファイルの実行
C言語・C++・C#
-
12
ファイルから読み取った改行文字を消す方法
C言語・C++・C#
-
13
多重定義が起きている?--lnk2005エラー:VC++
C言語・C++・C#
-
14
csvファイルを構造体に格納したいです
C言語・C++・C#
-
15
C言語で複数列のデータを1列のみ読み込みたい
C言語・C++・C#
-
16
別ファイルの構造体の値を読み込む、変えるには?2
C言語・C++・C#
-
17
C言語で特定列だけを抽出して配列に格納し、出力したいです。 読み込みファイル(read.txt) 0
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
別ファイルの構造体の値を読み...
-
複数行のデータのPOST処理に関して
-
エラーメッセージ(無効な間接...
-
配列同士の足し算のループ処理
-
fgetcsvでデータが何も表示され...
-
Resource id #3 と表示されま...
-
php Undefined variableエラー
-
smartyでページングするには
-
phpでCSVファイルの中身を多次...
-
◆速い、ファイル読み込みは?
-
C言語でCSVファイルの行数を読...
-
ヒアドキュメントの中のfor文
-
PHPでCSVの一部の行を編集したい
-
CSVファイルの最終行のデー...
-
phpメールフォームから送信され...
-
多次元配列の一次元目の最大値...
-
csvの内容を行単位で削除したい
-
PHP5でCSVの指定行データだけを...
-
preg_splitがうまくいかないの...
-
PHPでこのコード自体に意味は無...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
複数行のデータのPOST処理に関して
-
Resource id #3 と表示されま...
-
別ファイルの構造体の値を読み...
-
PHPでCSVの一部の行を編集したい
-
バイナリファイルの内容を、そ...
-
CSVファイルの最終行のデー...
-
ヒアドキュメントの中のfor文
-
stdClass Objectを連想配列のよ...
-
◆速い、ファイル読み込みは?
-
C言語でCSVファイルの行数を読...
-
phpでCSVファイルの中身を多次...
-
rubyで複数列のデータを一行に...
-
多次元配列の一次元目の最大値...
-
行数が30万件ほどあるCSVから、...
-
配列同士の足し算のループ処理
-
csvの内容を行単位で削除したい
-
FortranのOPEN文
-
CSVデータの行数カウントをした...
-
自動で番号を振りたい
-
While文を使って配列の中身を全...
おすすめ情報