C言語関係掲示板

過去ログ

No.319.縦横のデータを2列に並べ替え

[戻る] [ホームページ]
No.1984

文字列とポインタ配列について
投稿者---sato(2002/07/06 19:38:42)


いつもお世話になっています。satoと申します。

早速ですが,文字列の取り扱いを教えてください。
今,データファイルがあるのですが,2次配列のように並んだデータを
2列に並べ替えようとしています。具体的には,

時間,1秒,2秒,3秒,4秒,5秒,6秒
1分,10,11,12,13,14,15
2分,21,23,25,27,29,31
3分,50,51,52,53,54,55
<以下,延々と続く。2MB程>

というcsv形式のデータを

time data
1分1秒 10
1分2秒 11
1分3秒 12



とうい風に並べ替えようとしています。

宣言は以下のようにして,*m[200]のポインタ配列に1行目のタイトル
(時間,1秒,2秒,3秒,4秒,5秒,6秒)を格納して,2行目以降のデータを
fprintfで,ファイルに出力しようとしています。(なぜ,200かと言うと,
上記のデータは7列ですが,処理するデータは,列が120あるからです。)


char *m[200]; // 一行目の題名を取得
char time01[60]; // 一列目を文字として格納
double data[200]; // データ一時格納配列

for(i=0;i<line01;i++){ //データ行分実行
n01=n01+1; //カウンタ
if(n01==1){ //一行目の題名を取得。新しいファイルに別の題名を出力
fscanf(fp1,"%s,%s,%s,%s,%s,%s,",m[0],m[1],m[2],m[3],m[4],m[5]);
fprintf(fp2," time data \n");
}else{ //二行目(以降)のデータを取得
fscanf(fp1,"%s,%lf,%lf,%lf,%lf,%lf",time01,data[1],data[2],data[3],data[4],data[5]);
for(i=1;i<6;i++){ //縦に並べ替える
fprintf(fp2,"%s %s %lf\n",time01,m[i],data[i]);
} //end of for
} //end of if
} //end of for

たぶん,アドレスの渡し方か,ポインタ配列の扱い方自体が間違っているかと
思います。HPの第9章と第10章を読みましたが,なかなかうまくいきま
せん。ご教授の程をよろしくお願います。
(上記のプログラムを実行すると,エラーがでます。)

環境は,win95+bcc5.5(コンソール)です。
よろしくお願いします。

No.1987

Re:文字列とポインタ配列について
投稿者---かずま(2002/07/07 00:29:32)


    char   m[200][16];
    char   time01[60];
    double data[200];

    if (fscanf(fp1, "%15[^,],%15[^,],%15[^,],%15[^,],%15[^,],%15[^,],%15s",
        m[0], m[1], m[2], m[3], m[4], m[5], m[6]) != 7) exit(1);
    fprintf(fp2, " time data\n"); 

    for (i = 1; i < line01; i++) {
        if (fscanf(fp1, " %59[^,],%lf,%lf,%lf,%lf,%lf,%lf", time01, &data[0],
            &data[1], &data[2], &data[3], &data[4], &data[5]) != 7) exit(1);
        for (j = 0; j < 6; j++) {
            fprintf(fp2, "%s %s %f\n", time01, m[j], data[j]);
        }
    }

さて、問題です。
(1) char *m[200]; と char m[200][16]; の違いは何か。
(2) %s で , の直前までの文字列を読み込めるか。
(3) %59[^,] の直前のスペースの役割を説明せよ。
(4) data[0] は double で、値は不定だが、アドレスも不定か。
(5) 二重の forループに同じ変数を使ってよいか。
(6) printf に %lf は使えるか。

No.1998

Re:文字列とポインタ配列について
投稿者---sato(2002/07/07 15:56:23)


>(1) char *m[200]; と char m[200][16]; の違いは何か。
「char *m[200];」は,200個のchar型のポインタ配列(先頭アドレス)
「char m[200][16];」200*16の2次元配列で,大きさは固定で確保される。
と解釈してます。
>(2) %s で , の直前までの文字列を読み込めるか。
fscanfでは,フィールド幅か区切り文字(スペース,タブ,改行)で指定
すれば読めると思います。今回のcsv形式では,カンマ切りになっているので,
読めるかどうかわからなかったので,うまくいかない場合はエディタなどで
カンマをスペースに変換しようかと思っています。
>(3) %59[^,] の直前のスペースの役割を説明せよ。
その前に,%59[^,]の意味がわかりません。文字化けですか?
>(4) data[0] は double で、値は不定だが、アドレスも不定か。
質問のところでは省いていましたが,配列data[0]は「-1.0」で
初期化しています。(データに負の数は無いため,それで初期化しています。)
>(5) 二重の forループに同じ変数を使ってよいか。
これはケアレスミスです。お恥ずかしい。
>(6) printf に %lf は使えるか。
double型の書式制御文字列は%lfだったと記憶していますが,
違うのですか?


No.2107

Re:文字列とポインタ配列について
投稿者---かずま(2002/07/17 15:58:41)

問題は、「1分,10,11,12,13,14,15」という入力データの「1分」を char time01[60];
に scanf で取り込みたいということです。

%s で、「1分」だけを読み込むことは出来ません。これは分かりますね。%s は
スペースや、タブや、改行文字がくるまで、ずっと文字を読み込みつづけます。

scanf には、指定した文字からなる文字列を読み込む変換指定子 %[ ] があり、
それには、指定した文字列以外からなる文字列を読み込む機能もあります。

それが %[^,] です。これで「,」以外の文字からなる文字列を読み込みます。

char time01[60] ですから、60文字以上読み込むとたいへんです。そこで 59 と
いう制限をつけて、%59[^,] としました。これで、「1分」を time01 に読み込む
ことが出来ます。

No.2000

Re:文字列とポインタ配列について
投稿者---sato(2002/07/07 18:04:05)


おかげさまで,うまくいきました。
ありがとうございました。

追伸 データをテスト用の6行から,実際に用いる120行にして,
   プログラムを修正したら,新しい問題につまずきました
   No.1999を参照してください。
   C言語は,どこでも改行して良いと思っていたのですが,
   勘違いのようでした。