![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
大学で研究のため,プログラミングをしている者です.
現在、外部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.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.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.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
CSVファイルの特定行の削除
Visual Basic(VBA)
-
5
ボタンの配置を変更したい
C言語・C++・C#
-
6
カンマ区切りのデータを配列に読み込みたい
C言語・C++・C#
-
7
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
8
数字の入った配列をファイルへ出力。
C言語・C++・C#
-
9
ファイルから読み取った改行文字を消す方法
C言語・C++・C#
-
10
VC++から引数付きexeファイルの実行
C言語・C++・C#
-
11
多重定義が起きている?--lnk2005エラー:VC++
C言語・C++・C#
-
12
C言語 配列の長さの上限
C言語・C++・C#
-
13
freadでcsvファイルを読み込んだ後、改行コードを終端文字に変換し
C言語・C++・C#
-
14
適切な変換関数が存在しない???
C言語・C++・C#
-
15
別ファイルの構造体の値を読み込む、変えるには?2
C言語・C++・C#
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
別ファイルの構造体の値を読み...
-
ヒアドキュメントの中のfor文
-
undefined offset というエラー...
-
PHP5でCSVの指定行データだけを...
-
クッキーがよくわかりません
-
rubyで複数列のデータを一行に...
-
PHPで、CSVファイルを、指定し...
-
二次元配列の削除
-
文字列の文字一文字ずつを解析...
-
指定文字を含むファイル名の取得
-
preg_splitがうまくいかないの...
-
携帯絵文字変換スクリプトで20...
-
Resource id #3 と表示されま...
-
二次元文字列をポインタで操作...
-
プルダウンメニューにDBの内容...
-
配列をループでたくさん宣言し...
-
PHP 多次元配列変数のデータ受...
-
file_existsでファイル名の部分...
-
fgetc関数について
-
PHPについて教えて下さい。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
別ファイルの構造体の値を読み...
-
複数行のデータのPOST処理に関して
-
エラーメッセージ(無効な間接...
-
Resource id #3 と表示されま...
-
ヒアドキュメントの中のfor文
-
自動で番号を振りたい
-
C言語でCSVファイルの行数を読...
-
配列同士の足し算のループ処理
-
stdClass Objectを連想配列のよ...
-
PHPでCSVの一部の行を編集したい
-
phpを実行するとファイルダウン...
-
行数が30万件ほどあるCSVから、...
-
phpでCSVファイルの中身を多次...
-
php Undefined variableエラー
-
CSVデータの行数カウントをした...
-
csvの内容を行単位で削除したい
-
複数ファイルで、それぞれの行...
-
テキストデータから指定行の削除
-
rubyで複数列のデータを一行に...
-
PHP5でCSVの指定行データだけを...
おすすめ情報