
あらかじめ型のわかっているN行*M列のエクセルデータをCSV形式にし、
読み込むプログラムを作成しました。
そのプログラムを下に示します
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 確保するデータ保存領域の大きさ(N行×M列) */
#define N23
#define M6
/* データの区切り文字 */
#define SEP_DATA','
int csv_read(char filename[], double csv[N][M]) {
/* ファイルオープン */
FILE *fp;
if( (fp = fopen(filename, "r")) == NULL ) {
printf(" file open error!!\n");
return -1;
}
/* 1行毎に読み出し */
char line[256], *ptr;
int i, j, k;
i=0;
while (fgets(line, 256, fp) != NULL) {
printf("*%s", line);
ptr = line; j=0;
do{
/* line[j]から次のタブ文字までを数値に変換 */
csv[i][j] = atof(ptr);
/* 次のタブ文字の位置を探す */
ptr = strchr(ptr, SEP_DATA);
/* タブ文字の次の文字を示す */
if (ptr!=NULL) { ptr++; }
j++;
}while(ptr!=NULL && j<M);
i++;
}
/* ファイルクローズ */
fclose(fp);
return 0;
}
int main(int argv, char *argc[]) {
char filename[256];
if( argv > 1){
strcpy(filename, argc[1]);
} else {
printf("Please Input Filename:");
scanf("%s", filename);
}
/* データ保存用の領域を確保 */
double (*csvdata)[M];
csvdata = (double(*)[M])malloc(sizeof(double[M]) * N);
//malloc(sizeof(*csvdata) * N);
if ( csvdata == NULL ){
return -1;
}
int i,j;
/* 配列の初期化 */
for( i=0; i<N; i++) {
for( j=0; j<M; j++) {
csvdata[i][j] = 0.0;
}
}
/* CSVデータの読み込み */
if( csv_read(filename, csvdata) < 0 ) {
return -1;
}
/* 配列の出力 */
for( i=0; i<N; i++) {
printf("%lf", csvdata[i][0]);
for( j=1; j<M; j++) {
printf("\t%lf", csvdata[i][j]);
}
printf("\n");
}
free(csvdata);
csvdata = NULL;
return 0;
}
これをNとMがどんな値であれ読み込めるようにするにはどうすれいいでしょうか
No.6ベストアンサー
- 回答日時:
>あらかじめ型のわかっているN行*M列のエクセルデータをCSV形式にし、読み込むプログラムを作成しました。
>これをNとMがどんな値であれ読み込めるようにするにはどうすれいいでしょうか
要するに、N行M列のCSVファイルをフリーの動的サイズで処理したいということですね?
試験的にSCVファイルで一度実験してみて行数Nが合わないようでしたら SAFTY を+5行とか+10行とかで補正してください。
/* Sample program
----- 実行形式 -----
./a.out file_name
*/
#include <stdio.h>
#include <stdlib.h> /* exit() */
#include <errno.h> /* errno */
#define SIZE 256
#define SAFTY 0 /* もしもの行数をこれで補正 >5 */
int main(int argc, char *argv[])
{
char line[SIZE],*p;
int M, N;
FILE *fp;
if(argc != 2) return 0;
if((fp = fopen(argv[1],"r")) == NULL){
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* 取り合えず、1行読み込み */
fgets(line, SIZE, fp);
/* カンマ(,)の数を列数M 数える */
M = 1;
p = line;
while(*p){
if(*p++ == ',') M++;
}
printf("M= %d : %s", M, line);
/* シリンダーヘッドを末尾に移動し、行数N を求める */
fseek(fp, 0, SEEK_END);
N = ftell(fp) / (p - line) + SAFTY;
printf("N= %d\n", N);
/* ここで malloc()を使う */
//csvdata = (double(*)[M])malloc(sizeof(double[M]) * N);
/* シリンダーヘッドを最初に戻し */
fseek(fp, 0, SEEK_SET);
/* 以下、通常のCSVファイル処理を継続する(省略してます)。*/
while(fgets(line, SIZE, fp) != NULL){
printf("%s", line);
}
fclose(fp);
return 0;
}
この回答への補足
実行してみましたが、何も表示されず処理が終わってしまいました。
C++として実行していますので、
#include <string.h>
を追記しました
No.7
- 回答日時:
#4 です。
>実行してみましたが、動きませんでした
>>大きくは、冒頭の3行を直すだけで、「実際にいれる」ことができ
まさか、本当に3行を直した「だけ」で実行したのですか。
#3 のソースをそのまま実行してみて下さい。
データ配列が異なるので、思いどおりに出力しないのは当たり前ですが、「動く」はずです。
(再度動作確認済み)
>おそらく勘違いされていると思うのですが、
>NとMの値はcsvの行・列数にしたいので、
>defineで決めるのがそもそもおかしい気がするのですが
「NとMの値はcsvの行・列数」のあたりは、いじってませんし、
私が「defineで決める」ようにしたわけでもありません。
勘違いのしようがないのですが・・。
もし、勘違いしてたら、#3 で
>>(確認済み)
とはできませんよ。ダミーデータすらできないのだから。また、
>>なお、デバック段階では、N と M は下のように小さくし、ダミーデータもそれに揃えた方が楽です。
「NとMの値はcsvの行・列数」と認識しているからの記述です。

No.5
- 回答日時:
No.2です。
>ほとんど理解できていません
正直、何を目指しているのか理解できません。
もし、宿題などであれば、理解もしないで答えだけ提出してもすぐにバレてしまいますし、今後を考えれば難しくなればなるほど、自分では解決できなくなってしまいます。
差し出がましいようですが、実行環境があるようなので、1ステップずつ実行してみたり、あるいはprintf()などで値を確認するなどして、理解された方がいいでしょう。
No.3さんより
>メモリ確保関数を用いるより、変数の宣言のほうが楽です。
この言葉どおりで、まずは大きめに領域を確保しておき、それに代入するのがいいでしょう。
たとえば、N行=1000,M列=100ぐらいで。
また、静的(static double csvdata[N][M];)に領域を確保した方が安心安全です。
ソースを見ると、確かにポインターを使って難しそうに見えます。
しかし、やっていることは、1行読み込んでそれからカンマ区切りを見つけながら、浮動小数点文字列をdouble値に変換し、2次元配列に代入しているだけです。
No.4
- 回答日時:
#3 です。
>今は環境がないので実行できませんが、
★うぅ~、無銭飲食か~。
>これだと3行2列の形式にしか対応してないんじゃないですか?
>>なお、デバック段階では、N と M は下のように小さくし、
>これはコピペした時に空白が消えてしまっただけで、
★ならば正常に動きます。
>これをNとMがどんな値であれ読み込めるようにするにはどうすれいいでしょうか
>>N と M に変更があれば、コンパイルし直さなければなりません。
この回答への補足
実行してみましたが、動きませんでした
おそらく勘違いされていると思うのですが、
NとMの値はcsvの行・列数にしたいので、
defineで決めるのがそもそもおかしい気がするのですが
No.3
- 回答日時:
>・・既存のプログラムは少しいじっただけなのでほとんど理解できていません
>実際にいれる文が欲しいです
コンパイルしてみれば、少しは理解できると思います。
大きくは、冒頭の3行を直すだけで、「実際にいれる」ことができました(確認済み)。
★要は、#define N23 と、#define N 23 は大違い、ということです。
+++++++++++++++ 以降、蛇足 ++++++++++++++++++++++
>型っていうのはMとNの値です
N と M に変更があれば、コンパイルし直さなければなりません。
このようなプログラムでは、(コンパイルし直す必要のない動的な)メモリ確保関数を用いるより、変数の宣言(◆)のほうが楽です。
http://homepage3.nifty.com/mmgames/c_guide/q_mal …
なお、デバック段階では、N と M は下のように小さくし、ダミーデータもそれに揃えた方が楽です。
以上をふまえたものを示します、参考にして下さい。
大きな変更 // ******* の付いた行
追加 // ++++++++ の付いた行
(超蛇足:C++記述を、C記述へ直しちゃいました)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3 // *******
#define M 2 // *******
#define SEP_DATA ',' // *******
int csv_read( char filename[], double csv[N][M] )
{
FILE *fp;
char line[256], *ptr;
int i = 0, j;
if( ( fp = fopen( filename, "r" ) ) == NULL ){
printf( " file open error!!\n" );
return -1;
}
while( fgets( line, 256, fp ) != NULL ){
printf( "*%s", line );
ptr = line; j = 0;
do{
csv[i][j] = atof( ptr );
ptr = strchr( ptr, SEP_DATA );
if( ptr != NULL ){ ptr++; }
j++;
}while( ptr != NULL && j < M );
i++;
if( N <= i ) break; // ++++++++
}
fclose( fp );
return 0;
}
int main( int argv, char *argc[] )
{
int i, j;
char filename[256];
double csvdata[ N ][ M ]; // ◆ ++++++++
if( argv > 1 ){
strcpy( filename, argc[1] );
}else{
printf( "Please Input Filename:" );
scanf( "%s", filename );
}
for( i = 0; i < N; i++ ){
for( j = 0; j < M; j++ ){
csvdata[i][j] = 0.0;
}
}
if( csv_read( filename, csvdata ) < 0 ) return -1;
for( i = 0; i < N; i++ ){
printf( "%f", csvdata[i][0] ); // *** %lf
for( j = 1; j < M; j++ ){
printf( "\t%f", csvdata[i][j] ); // *** %lf
}
printf( "\n" );
}
return 0;
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
この回答への補足
今は環境がないので実行できませんが、
これだと3行2列の形式にしか対応してないんじゃないですか?
>#define N23 と、#define N 23
これはコピペした時に空白が消えてしまっただけで、実際には右側のように書いてあります
No.1
- 回答日時:
方法A
(1) とりあえず、一行読み込んで列数をカウント
(2) 一旦、行数カウントのためだけにファイルを読み込んで行数をカウント
(3) 必要なメモリを確保
(4) 今までと同じ流れでファイルの先頭から読み込み
方法B
とりあえず、一行読み込んで列数をカウント
一行分のデータを
次の行へのポインタ+配列
の線形リストにして、一行一行、
メモリ確保 → ファイルから一行読み込み → 確保したメモリにデータをセット
とする。
二次元配列でなければならないのであれば、一旦、線形リストの形で読み込んでおいて、
全行読み込んだ後でリストの先頭からたどって二次元配列にセットしなおすとか。
線形リストについては、
http://www.cc.kyoto-su.ac.jp/~yamada/ap/list.html
とか、検索するといろいろ出てくると思います。
この回答への補足
プログラムを作成した、
とは言っても既存のプログラムは少しいじっただけなので
ほとんど理解できていません
実際にいれる文が欲しいです
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
#defineが使用するメモリ領域に...
-
【C言語】全角文字の配列を、全...
-
Enterキーを押されたら次の処理...
-
「Aに対するBの割合」と「Aに対...
-
有効数字について 以前質問をし...
-
C言語での引数の省略方法
-
C言語を実行すると-infが出てき...
-
数学 確率変数Xは、X=2またはX...
-
DWORDの実際の型は何でしょうか
-
ある商品のロス率を5%見込み、...
-
プログラムでの数字につく”f”の...
-
複数桁10進数の*桁目だけを抽出...
-
*をユーザーが入力した数字の数...
-
エクセルの問題です。絶対値の...
-
16進数 加算 減算 C言語
-
2÷3などの余りについて
-
Win32APIでのエディットボック...
-
プログラムで関数は使わない方...
-
異なる文字列のマッチングを、D...
-
【指数・対数】
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
【C言語】全角文字の配列を、全...
-
#defineが使用するメモリ領域に...
-
C言語で複数列のデータを1列の...
-
printf による16進表示について
-
char型2つを結合し、short型に...
-
空白を含んだ文字列がうまく格...
-
矢印キーを押下してコンソール...
-
C++で指定文字列のカウント方法...
-
コマンドファイルから、ビット...
-
C言語のプログラムで、途中で止...
-
終了条件Ctrl+zについて,結果表...
-
配列への文字列の格納について
-
困ってます!書き方がわかりま...
-
ファイルから数字列を16進数の...
-
fread(),fwrite()等について
-
0x8, スペース, 0x8をプログラ...
-
static付き宣言の初期化
-
構造体メンバの初期化
-
c言語で文書を読み込み、単語の...
おすすめ情報