Thread View: fj.lang.c
14 messages
14 total messages
Started by Tomoaki Chiba
Fri, 20 Mar 1998 00:00
[Q]区切りなしデータを文字型でない配列に読むには?
Author: Tomoaki Chiba
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
194 lines
8357 bytes
8357 bytes
千葉@東北大 と申します。
fj.test 以外には初投稿ですので、不備がありましたら御指摘下さい。
また一部に、Subjectに示した一般的な問題でなく、自分の作業環境(あるいは
不適切な関数使用)に由来する?と思われる部分もあるのですがお許し下さい。
# おまけに180行ぐらいと長くなってしまいました。すみません。
ちなみに自分の作業環境は SPARCstation5 で SunOS Release 4.1.3-JLE1.1.3_U1
の gcc version 2.7.2.1 と、
パソコン(ハンドメイド?オーダーメイド?)で FreeBSD 2.2.2-RELEASE #0
の gcc version 2.7.2p を使用しています。
------------------------------------------------------------------------
Subjectが長いのはよろしくないと思って切ってしまいましたが、正確には
[Q]長くて区切り文字のない文字列(数字列)を、ファイルから、行単位で
(一行丸ごとという意味)、文字型でない配列に、可能な限り簡潔に、
読み込むには?
といったところです。
「可能な限り簡潔に」とは、ソースコードとしても短く、かつ、オンライン
マニュアルを読めて「はじめてのC」(技術評論社)程度にC言語の知識を
持ち合わせている(C++はほとんどわからない)人が、ソースプログラム
を読んで多くてもせいぜい10回程度(そのプログラムを)読み返すだけで理
解できるレベルと考えて下さい。
具体的に何をしたいかといいますと各行が
13202341795053000891325518391019052
のように数字のみで成り立っているデータを5桁の数字の並び、すなわち
13202 34179 50530 00891 32551 83910 19052
としてそれぞれを整数型(int)もしくは実数型(floatかdouble)の変数に入れた
いのです。ここで 00891 は 891 にというように先頭から続く 0 は取り去っ
た値を入れます。
もう一つ重要なのはこのデータの各行は 200~400×5 個位の数字から成り立
っているということです。すなわち行ごとに例えば Data[350] のような配列
に読み込むことを考えます。
-------------------------------------------------------------------
なぜこんなことを考えているかというと、最初は
int i;
FILE *fp; /* データファイルのファイルポインタ */
char CharArray[6]; /* 5バイト分?のデータを一時的に読み込む配列 */
double DblData[350]; /* 実際にデータを格納する配列 */
for(i=0; i<350; i++) {
fread(CharArray, 5, 1, fp);
CharArray[6] = '\0';
DblData[i] = atof(CharArray);
}
といったプログラムで上述のようなデータを読んでいました。
----------------------------------------------------------------------
ここで、ループを使って5文字分ずつ読んでいくのではなく、一行分ずつ
一気に読んでしまいたいという考えが浮かんできました。そこでまずは
char CharArray2D[350][5];
fread(CharArray2D, 5, 350, fp);
for(i=0; i<350; i++)
DblData[i] = atof(CharArray2D[i]);
のようなものを考えました。ところが、atof系の関数の引数は"文字列"であり
空文字('\0')までを文字列とみなすので、
変数 中身
DblData[0] 13202341795053000891325518391019052
DblData[1] 341795053000891325518391019052
DblData[2] 5053000891325518391019052
のように引数の位置から後が全て代入されてしまいます。
CharArray2D ではなく CharArray1D[350*5] を使っても同じです。
DblData[i] = 10000 * ( CharArray2D[i][0] - '0' ) \
+ 1000 * ( CharArray2D[i][1] - '0' ) \
+ 100 * ( CharArray2D[i][2] - '0' ) \
+ 10 * ( CharArray2D[i][3] - '0' ) \
+ 1 * ( CharArray2D[i][4] - '0' );
のようにすれば(足し引き間違ってたらすみません)、atof系の関数は使わな
くてもよいのですが、これはとりあえず「可能な限り簡潔」ではないとさせて
下さい。
ちなみに fgets を使って1行丸ごと読む方法でも上と同様な「冗長さ」が生ま
れると思われます。
---------------------------------------------------------------------
そこで次にダイレクトに
FILE *fp; /* データファイルのファイルポインタ */
double DblData[350]; /* 実際にデータを格納する配列 */
fread(DblData, 5, 350, fp);
などということはできないかと思ってやってみました(というかこれで
すんなりうまくいっていたらニュースには投稿していませんでしたが)。
---(以下、自分の作業環境依存の話?)-------------------------------
ところが、doubleやfloatには 0.0 より小さい(E-10~E-19のオーダー)値、
int には 750000000~950000000 くらいの大きな値が入ってしまいます。
fread(DblData, 5, 1, fp);
fread(DblData, sizeof(DblData[0]), 350, fp);
fread(DblData, sizeof(DblData[0]), 1, fp); /* これできちんと読み込め
ないのはおかしい? */
のようにもしてみましたが、結果はいずれも同じでした。
よって、上の結果は自分の環境(OSやコンパイラ)に依存している可能性
もあります。
ちなみにfreadの返却値はいずれの場合も3つ目の引数に一致しています。
アドレス演算子&を用いて
fread(&DblData[0], sizeof(DblData[0]), 1, fp);
のようなことをしても同じ結果になります。
-------------------------------------------------------------------
ポインタを使って
double *DblDataP;
fread(DblDataP, 5, 1, fp);
のようなことをすると、SunOS では Segmentation fault します。デバッガ
(dbx)で調べると上の fread を呼び出した場所で
signal SEGV (segmentation violation) in memcpy at 0xef77aa2c
memcpy+0x17c: stb %o4, [%o0]
で止まります。
(デバッガも良く知らないので詳しくはわかりませんが、fread から memcpy
を呼び出していて、その memcpy のところで領域のアドレス違反を侵して
いるといったところでしょうか?)
FreeBSDではアドレス演算子を用いた時と結果は同じです。
さらに void *型や int型や int *型その他にキャストして当てずっぽう的に
試してみましたが、今度はFreeBSD で Bus error して memmove で領域違反?
と言われたり、SunOSでは上と同じ結果になったりで解決の手がかりにもなり
そうにありませんでした。
# どういうキャストをした中身がきちんとキャスト前の値を参照できるかに
# ついての知識は自分にはほとんどありません。
---(以上、自分の作業環境依存の話?)--------------------------------
fread でうまくいかないのは作業環境が原因のような気がしてきたので、
今度は fscanf を使えないかと考えてみました。
fscanf では フォーマット文字列(2つ目の引数)中で
"%5f%5f%5f"
のように読み込む「文字数」を指定して文字型以外の変数にも読み込めます。
フォーマット文字列も連結の繰り返しで簡潔に記述して作成することがなんと
かできそうです。
しかし長い一行を一気に読むことを考えた場合、3つ目の引数以降の、読み込
み先のアドレスを指定する部分はそれこそ
fscanf(fp, FORMAT, &DblData[0],&DblData[1],&DblData[2],.....
というのが &DblData[349]); まで続く記述がソースファイル中にそのまま横
たわっている姿しか思い浮かんできません。
# そもそも行の長さが最大何文字までとどこかで決まっていたような気もし
# ます。
-----------------------------------------------------------------------
以上が自分で考えて思考錯誤してみて出てきた結果です。
初心者にも理解できる、行データを丸ごと読み込む、簡潔で抜けるようなアイ
ディアが何かないものでしょうか。
自分のやり方では fread の使い方が変だというような御指摘もお待ちしてい
ます。
---------------------------------------------------------------
Name : Tomoaki Chiba 千葉 智章
: Inst.Geol.Paleon.Dep.Geo.Env.Sci.Tohoku.Univ
: 東北大学理学部地圏環境科学科地質学古生物学教室4年
E-mail : chiba@dges.tohoku.ac.jp
FAX : 022-217-6634
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: Hiroyuki Minesita
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
80 lines
3586 bytes
3586 bytes
From article <6esjd9$4t@sakunami.gw.tohoku.ac.jp>
by chiba@dges.tohoku.ac.jp
> [Q]長くて区切り文字のない文字列(数字列)を、ファイルから、行単位で
> (一行丸ごとという意味)、文字型でない配列に、可能な限り簡潔に、
> 読み込むには?
根本的にはデータ構造が悪いのでそれを考え直すのが一番です。
#身も蓋もありませんが……(^^;
> なぜこんなことを考えているかというと、最初は
>
> int i;
> FILE *fp; /* データファイルのファイルポインタ */
> char CharArray[6]; /* 5バイト分?のデータを一時的に読み込む配列 */
> double DblData[350]; /* 実際にデータを格納する配列 */
> for(i=0; i<350; i++) {
> fread(CharArray, 5, 1, fp);
> CharArray[6] = '\0';
> DblData[i] = atof(CharArray);
> }
概ねこういう形になるでしょう。
多分、他を試してもこれ以上は簡単にならなかったんじゃないで
しょうか?
> ここで、ループを使って5文字分ずつ読んでいくのではなく、一行分ずつ
> 一気に読んでしまいたいという考えが浮かんできました。そこでまずは
>
> char CharArray2D[350][5];
> fread(CharArray2D, 5, 350, fp);
> for(i=0; i<350; i++)
> DblData[i] = atof(CharArray2D[i]);
ループを使っていますよね?
> そこで次にダイレクトに
> FILE *fp; /* データファイルのファイルポインタ */
> double DblData[350]; /* 実際にデータを格納する配列 */
> fread(DblData, 5, 350, fp);
>
> などということはできないかと思ってやってみました(というかこれで
> すんなりうまくいっていたらニュースには投稿していませんでしたが)。
何故出来ると考えられるかが問題な気がします。(^^;
根本的に変数がメモリにどういう風に存在するのかを理解する
べきだと思います。
> ---(以下、自分の作業環境依存の話?)-------------------------------
>
> ところが、doubleやfloatには 0.0 より小さい(E-10~E-19のオーダー)値、
> int には 750000000~950000000 くらいの大きな値が入ってしまいます。
>
> fread(DblData, 5, 1, fp);
> fread(DblData, sizeof(DblData[0]), 350, fp);
> fread(DblData, sizeof(DblData[0]), 1, fp); /* これできちんと読み込め
> ないのはおかしい? */
読めないのが当然です。
> のようにもしてみましたが、結果はいずれも同じでした。
> よって、上の結果は自分の環境(OSやコンパイラ)に依存している可能性
> もあります。
依存していません。言語には多少依存しているかもしれませんが……(^^;
sizeof(DblData[0]) の値がいくつになるかを確認しましょう。
> アドレス演算子&を用いて
これ以下はポインタを理解していないと見受けられます。
---
@) ---------------------- 〃
(・> ヾ<・)
ι ν 峯下博幸 ( ~彡
(m_m)っ ---------------------- κκ
Re: [Q]$B6h@Z$j$J$7%G!<%?$rJ8;z7?$G$J$$G[Ns$KFI$`$K$O!)(B
Author: Jun TAKE-UCHI
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
14 lines
1088 bytes
1088 bytes
<6esjd9$4t@sakunami.gw.tohoku.ac.jp>$B$N5-;v$K$*$$$F(B
chiba@dges.tohoku.ac.jp$B$5$s$O=q$-$^$7$?!#(B
|------------------------------------------------------------------------
|
|Subject$B$,D9$$$N$O$h$m$7$/$J$$$H;W$C$F@Z$C$F$7$^$$$^$7$?$,!"@53N$K$O(B
|
|[Q]$BD9$/$F6h@Z$jJ8;z$N$J$$J8;zNs!J?t;zNs!K$r!"%U%!%$%k$+$i!"9TC10L$G(B
| $B!J0l9T4]$4$H$H$$$&0UL#!K!"J8;z7?$G$J$$G[Ns$K!"2DG=$J8B$j4J7i$K!"(B
| $BFI$_9~$`$K$O!)(B
$B0l9T$N:GBgJ8;z?t$,7h$^$C$F$$$k$N$G$7$?$i!"0lEY%P%C%U%!$KFI$_9~$s$@8e(B
memcpy()$B$+(Bstrncpy()$B$G#5J8;z$:$D@Z$j=P$9$N$O$I$&$G$7$g$&$+!)(B
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: shino
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
65 lines
2762 bytes
2762 bytes
しのです。
Tomoaki Chiba wrote in message <6esjd9$4t@sakunami.gw.tohoku.ac.jp>...
>
>千葉@東北大 と申します。
>
>Subjectが長いのはよろしくないと思って切ってしまいましたが、正確には
>
>[Q]長くて区切り文字のない文字列(数字列)を、ファイルから、行単位で
> (一行丸ごとという意味)、文字型でない配列に、可能な限り簡潔に、
> 読み込むには?
>
>といったところです。
>「可能な限り簡潔に」とは、ソースコードとしても短く、かつ、オンライン
>マニュアルを読めて「はじめてのC」(技術評論社)程度にC言語の知識を
>持ち合わせている(C++はほとんどわからない)人が、ソースプログラム
>を読んで多くてもせいぜい10回程度(そのプログラムを)読み返すだけで理
>解できるレベルと考えて下さい。
「はじめてのC」を読んでないので、どこまで「簡潔」に出来たか解りませんが、
この記事の後ろにサンプルの関数を付けます。
>もう一つ重要なのはこのデータの各行は 200~400×5 個位の数字から成り立
>っているということです。すなわち行ごとに例えば Data[350] のような配列
>に読み込むことを考えます。
これは、一行あたりのデータの個数は可変ということですか?
もし不変なら、下の関数を使った後にfreeせずに済むのですが・・・。
/*
引数:
data 格納するdouble型へのポインタへのポインタ
str 取り出したいデータの数字が格納された文字列
vlen データ一つあたりの文字数
戻り値:
データの数(*dataの要素数)
*/
int GetValues(double **data, char *str, int vlen)
{
int i, ret;
char *buf;
ret = strlen(str) / vlen;
*data = (double*)malloc(sizeof(double)*ret+1);
buf = (char*)malloc(vlen+1);
for(i = 0; i < ret; i++)
{
strncpy(buf, str+(i*vlen), vlen);
buf[vlen] = '\0';
(*data)[i] = atof(buf);
}
free(buf);
return ret;
}
--
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
HandleName:しの
E-Mail : shino@planet.forum.or.jp
HomePage : http://www2.tky.3web.ne.jp/~shino211/index.shtml
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
Re: [Q]区切りなしデータを文字型
Author: Kusakabe Youichi
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
89 lines
3663 bytes
3663 bytes
Tomoaki Chiba (chiba@dges.tohoku.ac.jp) wrote:
: fj.test $B0J30$K$O=iEj9F$G$9$N$G!"ITHw$,$"$j$^$7$?$i8f;XE&2<$5$$!#(B
fj.test$B$ON}=,MQ$N(BNewsGroup$B$G$O$J$$$G$9$h!#(B
: $B%G!<%?$N3F9T$O(B 200$B!A(B400$B!_(B5 $B8D0L$N?t;z$+$i@.$jN)$C$F$$$k$H$$$&$3$H$G$9!#(B
: $B$9$J$o$A9T$4$H$KNc$($P(B Data[350] $B$N$h$&$JG[Ns$KFI$_9~$`$3$H$r9M$($^$9!#(B
$B$I$&$7$F(B200$B!A(B400$B$J$N$K!V(B350$B!W$J$s$F$$$&@k8@$r$9$k$N$G$7$g$&$+(B?
: DblData[i] = 10000 * ( CharArray2D[i][0] - '0' ) \
: + 1000 * ( CharArray2D[i][1] - '0' ) \
: + 100 * ( CharArray2D[i][2] - '0' ) \
: + 10 * ( CharArray2D[i][3] - '0' ) \
: + 1 * ( CharArray2D[i][4] - '0' );
: $B$N$h$&$K$9$l$P!JB-$70z$-4V0c$C$F$?$i$9$_$^$;$s!K!"(Batof$B7O$N4X?t$O;H$o$J(B
: $B$/$F$b$h$$$N$G$9$,!"$3$l$O$H$j$"$($:!V2DG=$J8B$j4J7i!W$G$O$J$$$H$5$;$F(B
: $B2<$5$$!#(B
$B$&!<$`$=$l$J$j$K4J7i$@$H$*$b$$$^$9$,$M!#(B
5$B2sJ,$r%k!<%W$K$9$l$P(B2$B9T$G=q$1$^$9$7!#(B
: $B$=$3$G<!$K%@%$%l%/%H$K(B
: FILE *fp; /* $B%G!<%?%U%!%$%k$N%U%!%$%k%]%$%s%?(B */
: double DblData[350]; /* $B<B:]$K%G!<%?$r3JG<$9$kG[Ns(B */
: fread(DblData, 5, 350, fp);
: $B$J$I$H$$$&$3$H$O$G$-$J$$$+$H;W$C$F(B
$B$J$<!V(Bdouble$B!W$J$s$F$$$&$b$N$,=P$F$/$k$N$G$7$g$&(B?
$B$7$+$b$=$l$,!V%@%$%l%/%H$K!W$C$F$$$&$N$,0UL#ITL@$G$9!#(B
$B$=$b$=$b!"$=$N$"$?$j$NM}2rITB-$,860x$N$h$&$G$9$M!#(B
$B$H$$$&$o$1$G!"(B
: ---$B!J0J2<!"<+J,$N:n6H4D6-0MB8$NOC!)!K(B-------------------------------
: ---$B!J0J>e!"<+J,$N:n6H4D6-0MB8$NOC!)!K(B--------------------------------
$B$N$"$?$j$O!VL5BL$J9M;!!W$K$J$C$A$c$C$F$^$9$M!#(B
: $B<+J,$N$d$jJ}$G$O(B fread $B$N;H$$J}$,JQ$@$H$$$&$h$&$J8f;XE&$b$*BT$A$7$F$$$^$9!#(B
$BJQ$G$9!#(B
: $B=i?4<T$K$bM}2r$G$-$k!"9T%G!<%?$r4]$4$HFI$_9~$`!"4J7i$GH4$1$k$h$&$J%"%$(B
: $B%G%#%"$,2?$+$J$$$b$N$G$7$g$&$+!#(B
$B$I$&$7$F$b!V(Bscanf$B!W7O$N4X?t$,;H$$$?$$!#$=$l$r!V4J7i!W$@$H;W$C$F$$$k(B
$B$H$$$&$N$J$i$P!"$?$H$($P!"0J2<$N$O$I$&$G$7$g$&$+(B?
($B$$$^$3$N>l$G;n$;$J$$$N$G;n$7$F$J$$$G$9!#$"$7$+$i$:(B)
---$B$3$3$+$i(B-------------------------------------------------------------------
#include <stdio.h>
#include <ctype.h>
#define MAX 400
#define FIGURE 5
main()
{
int data[MAX];
char buf[FIGURE * MAX + 2];
int i;
while (fgets(buf, FIGURE * MAX + 2, stdin) != NULL) {
for (i = 0; i < MAX && isdigit(buf[i * FIGURE]); i++)
sscanf(&buf[FIGURE * i], "%*d", FIGURE, &data[i]);
}
}
---$B$3$3$^$G(B-------------------------------------------------------------------
$BOC$NFbMF$+$i(Bint$B$O(B16bit$B$G$O$J$$4D6-$@$HM=A[$5$l$^$9$,!"(B
16bit$BDxEY$N(Bint$B$@$H!"(B5$B7e$N(B10$B?J?t$O(Bint$B$KG<$^$i$J$$$N$GCm0U$,I,MW$G$9$M!#(B
$B$"$H!"(Bgcc$B$N(Bsscanf()$B$G!V(B*$B!W$,(B $B;H$($k$+$I$&$+CN$i$J$$$N$G$9$,!"(B
sscanf(&buf[FIGURE * j], "%*d", FIGURE, &data[j]);
$B$,$@$a$@$C$?$i(B
sscanf(&buf[FIGURE * j], "%5d", &data[j]);
$B$H$G$b$7$F$_$F$/$@$5$$!#(B
$B%X(B_$B%X(B ________________________
$B%_!&!&(B $B%_(B void@merope.opus.or.jp
( $B!k(B )$B!A(B $BF|2<ItM[0l(B
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: Masao Seki
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
73 lines
2791 bytes
2791 bytes
Tomoaki Chiba wrote:
> 「可能な限り簡潔に」とは、ソースコードとしても短く、かつ、オンライン
> マニュアルを読めて「はじ゚てのC」(技術評論社)程度にC言語の知識を
> 持ち合わせている(C++はほとんどわからない)人が、ソースプログラム
> を読んで多くてもせいぜい10回程度(そのプログラムを)読み返すだけで理
> 解できるレベルと考えて下さい。
以下のようにするのは、どんなものでしょう。5、6回読めば、肝の部分は
理解できると思いますが。
文字列長さに半端があった時、先頭データで吸収するのか最後でするのか、
仕様がなかったので、楽な先頭の方にしました。
fgetsで文字列データをとりこんだ時、改行コードも取り込まれるシステム
を想定しています。エラー処理その他の、御質問の趣旨からはずれると思わ
れる部分は、かなり手抜きしています。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLENG 500
#define MAXLINE 100
#define WID 5
int main(int ac, int **av)
{
int m, n, n9, jverb = 0;
int ndata[MAXLINE][MAXLENG/WID];
unsigned char cbuf[MAXLENG+1], *p, save;
size_t len;
FILE *fp = stdin;
if (ac > 1) jverb = 1;
cbuf[MAXLENG] = '\0';
for (m=0; m < MAXLINE; m++) {
if (fgets(cbuf, MAXLENG, fp) == NULL || feof(fp)) break;
else {
len = strlen(cbuf) - 1;
if (cbuf[len] != '\n') {
cbuf[10] = '\0';
fprintf(stderr, "too long line. %d: |%s ・・・ %s|\n",
m, cbuf, cbuf+MAXLENG-10);
return 1;
}
}
for (; isspace(cbuf[len-1]); len--) ;
n9 = (len + WID -1)/WID;
p = cbuf + ((len-1) % WID) + 1;
save = *p; *p = '\0';
ndata[m][0] = atoi(cbuf); *p = save;
for (n=1; n < n9; n++, p += WID) {
save = p[WID]; p[WID] = '\0';
ndata[m][n] = atoi(p);
p[WID] = save;
}
if (jverb) {
fprintf(stdout, "%3d: ", m);
for (n=0; n < 5; n++)
fprintf(stdout, "%*d ", WID, ndata[m][n]);
fprintf(stdout, "・・・ ");
for (n=n9-5; n < n9; n++)
fprintf(stdout, "%*d ", WID, ndata[m][n]);
fprintf(stdout, "\n");
}
}
return 0;
}
--
関 正生 <masao.seki@fujixerox.co.jp || ma-seki@gb3.so-net.or.jp>
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: keizi kounoike
Date: Fri, 20 Mar 1998 00:00
Date: Fri, 20 Mar 1998 00:00
75 lines
2786 bytes
2786 bytes
鴻池といいます。
現在Cを勉強中で,レベルは千葉さんが述べている要件に合致していると思います。
それで,それなりに考えたのを書いてみました。
>千葉@東北大 と申します。
>
>[Q]長くて区切り文字のない文字列(数字列)を、ファイルから、行単位で
> (一行丸ごとという意味)、文字型でない配列に、可能な限り簡潔に、
> 読み込むには?
>
>といったところです。
>「可能な限り簡潔に」とは、ソースコードとしても短く、かつ、オンライン
>マニュアルを読めて「はじめてのC」(技術評論社)程度にC言語の知識を
>持ち合わせている(C++はほとんどわからない)人が、ソースプログラム
>を読んで多くてもせいぜい10回程度(そのプログラムを)読み返すだけで理
>解できるレベルと考えて下さい。
>
-------------以下の通り------------------
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define su 5
main(){
int i=0,j=1,c,co=0;
char temp[]="aaaaaa";
long *p,LN,RN;
FILE *fp;
if ((fp=fopen("data-1","r"))==NULL){
printf("can't open data-1\n");
exit(1);
}
fseek(fp,0,SEEK_END);
LN=(long)ftell(fp);
RN=LN/(sizeof(char)*su)+1;
if ((p=(long *)malloc(sizeof(long)*RN))==NULL)
printf("can't malloc\n");
rewind(fp);
while((c=fgetc(fp))!=EOF){
if (isdigit(c)){
temp[i]=c;
i++;
}
else
continue;
if (i==su) {
p[j]=atol(temp);
j++;
co++;
for(i=0;i<(su+1);temp[i]='a',i++);
i=0;
}
}
if (isdigit(temp[0])){
co++;
p[j]=atol(temp);
}
p[0]=co;
/* data print */
printf("total number of record = %d\n",p[0]);
for(i=1;i<=p[0];i++)
printf("%d\n",p[i]);
}
----------------------------------------------
ただ,これは千葉さんの1行単位で読むという条件からずれており,数列がファイル
の最後までつながっているとみなし,それを5文字単位で切り取るように,勝手に条
件を変更したので論外かも知れませんが。
Re: [Q]区切りなしデータを文字型
Author: Masao Seki
Date: Sat, 21 Mar 1998 00:00
Date: Sat, 21 Mar 1998 00:00
11 lines
975 bytes
975 bytes
Kusakabe Youichi wrote: > あと、gccのsscanf()で「*」が 使えるかどうか知らないのですが、 > sscanf(&buf[FIGURE * j], "%*d", FIGURE, &data[j]); > がだめだったら scanf系の書式の中の「*」は、代入の抑制ですよ、日下部さん。 -- 関 正生 <masao.seki@fujixerox.co.jp || ma-seki@gb3.so-net.or.jp>
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: Masahiro Kondo
Date: Sat, 21 Mar 1998 00:00
Date: Sat, 21 Mar 1998 00:00
32 lines
2000 bytes
2000 bytes
こんばんは、近藤といいます。
元記事が分からないので・・・外しているかも??
shino wrote:
> >[Q]長くて区切り文字のない文字列(数字列)を、ファイルから、行単位で
> > (一行丸ごとという意味)、文字型でない配列に、可能な限り簡潔に、
> > 読み込むには?
> >
「長くて区切り文字のない文字列」って?
区切り文字の定義があいまいですが・・・(区切りが無ければ行って観念もない
ですね?)
行の区切りって、どう判断するのでしょうか?(区切りが無いから判断出来ない
のでは?)
仮にCR/LF(DOSの場合)が行の区切りだとすると、CR/LFが来るまで読み込むの
は、
だめですか? 最大長(一行の)が分かっていれば(1Kでも4Kでも)
それだけの領域を確保して、fgetsで読めないですか?
もし、本当に一行の文字数(または、行末の文字がCR/LF以外の場合)が分から
なければ、
一文字づつ行末(文字)が来るまで読み込んで行頭の位置から、行末の位置まで
の領域を
確保して再読み込みをしなくてはなりません。
ちなみに、freadは行なんて意識はないです。 < 要求されたバイト数だけ読
み込みます。
(ファイルにデータがあれば)
/***************************************
Masahiro Kondo (近藤 正博)
mako@mail.raidway.or.jp
***************************************/
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: Tomoaki Chiba
Date: Mon, 23 Mar 1998 00:00
Date: Mon, 23 Mar 1998 00:00
259 lines
12917 bytes
12917 bytes
千葉@東北大です。
近々引っ越すので、自宅で荷作り&引越し屋さんと打ち合せしており、
フォローが送れました。しかも昨日はうちの建物が停電だったらしい
のでもしメールを送って頂いた方がいらしたら届かなくて済みません。
その間、いろいろな方法を提案して頂けてありがたく思います。
(mineshitaさん、takeuchiさん、shinoさん、voidさん、masao.seki
さん、kounoikeさん、makoさん、どうもありがとうございました。)
皆さん御指摘の通り、データや条件の説明としてはっきりしない部分
が多数ありましたので、以下にフォローする形で明示します。
-------------------------------------------------------------------
fj.lang.cの<6esmcd$30l$1@sunny.njk.co.jp>の記事において
JST時間1998年03月20日(金)12時04分45秒頃、minesita@rd.njk.co.jpさんは
書きました。
| 根本的にはデータ構造が悪いのでそれを考え直すのが一番です。
| #身も蓋もありませんが……(^^;
自分もその通りだと思います。実は元データは
建設省国土地理院 発行・刊行
(財)日本地図センター 発売
数値地図メッシュ(標高)
のものです。内容はその名のごとく日本にメッシュ状に縦横線を引いて
分割してその各メッシュにおける標高の代表値をCD-ROMに格納し
たものです。50m,250m,1kmそれぞれの間隔で区切ったものがあります。
詳しくは
http://www.jmc.or.jp/suchiindx.html
の該当部分にあります。
データの格納形式はファイル仕様という項目に書いてあります。
http://www.jmc.or.jp/250m/doc/info250.htm
などです。
各ファイルには250m,1kmメッシュでは国土地理院の形式である1次メッ
シュ(緯度1/3度、経度1度)の範囲、50mメッシュでは同2次メッシュ
(1次メッシュの1/64の面積すなわち1/8の辺長)の範囲のデータが入
っています。
実際に計算してみるとわかりますが、250mメッシュでは320x320、1km
では80x80、50mでは200x200のデータがそれぞれのファイルに入ってい
ます。
各ファイルはそのメッシュのデータがいろいろ入っているファイルヘッ
ダ(標高データだけ読む時は飛ばす)がまずあって、その後に標高デー
タが「緯度毎に一行ずつ」格納されています。(ファイルフォーマット
およびレコード構成のところを参照して下さい。)
ただし各行の先頭にはメッシュコードとレコード番号なるものが入れて
あって、各行の最後は「復帰・改行(CR・LF)」です。(レコード
フォーマットを参照して下さい。)
# ちなみにこのデータを扱う人は、いったんスペース区切りを入れた
# 形式にデータを変換して別に保存している場合が多いようです。
# 一応、毎回計算の度にCD-ROMにアクセスする必要があるなど
# という使い方はしておりません。
# ただ自分は全国のデータをハードディスクに保存しようとして、
# "file sytem full"を起こしたことがありましたが...
| > なぜこんなことを考えているかというと、最初は
| >
| > int i;
| > FILE *fp; /* データファイルのファイルポインタ */
| > char CharArray[6]; /* 5バイト分?のデータを一時的に読み込む配列 */
| > double DblData[350]; /* 実際にデータを格納する配列 */
| > for(i=0; i<350; i++) {
| > fread(CharArray, 5, 1, fp);
| > CharArray[6] = '\0';
| > DblData[i] = atof(CharArray);
| > }
|
| 概ねこういう形になるでしょう。
| 多分、他を試してもこれ以上は簡単にならなかったんじゃないで
| しょうか?
# これより簡単な方法はやはりないのでしょうか?
| > ここで、ループを使って5文字分ずつ読んでいくのではなく、一行分ずつ
| > 一気に読んでしまいたいという考えが浮かんできました。そこでまずは
| >
| > char CharArray2D[350][5];
| > fread(CharArray2D, 5, 350, fp);
| > for(i=0; i<350; i++)
| > DblData[i] = atof(CharArray2D[i]);
|
| ループを使っていますよね?
説明不足ですみません。この段階ではとりあえず関数freadで一行の
データをまず丸ごと読んでしまうことを考えていました。しかしこれ
では文字型配列に読み込んだデータを切り出してintやdoubleといっ
た配列に読み込まなくてはいけないのです。つまり問題の形式のデー
タを「freadで文字型配列に読み込むがごとく」(これだとループも
いらず表現も短い一行で済んでしまう、後述の「ダイレクト」とはこ
れを表したくて使いました)、他の型の配列に読む方法はないものか
と思ったのです。「簡潔」というのにできればこの「ダイレクト」も
加えて頂くとありがたいです。
| > そこで次にダイレクトに
| > FILE *fp; /* データファイルのファイルポインタ */
| > double DblData[350]; /* 実際にデータを格納する配列 */
| > fread(DblData, 5, 350, fp);
| >
| > などということはできないかと思ってやってみました(というかこれで
| > すんなりうまくいっていたらニュースには投稿していませんでしたが)。
|
| 何故出来ると考えられるかが問題な気がします。(^^;
| 根本的に変数がメモリにどういう風に存在するのかを理解する
| べきだと思います。
「ダイレクト」を実行すべく、このようにして読めれば儲け物と思ってやって
みましたが、やはりだめでした。
freadがどういうデータのやりとりをしているのか探るべく、stdio.h(自分の
環境では /usr/include にある)を覗いてみましたが、「C言語で書いてある
ようだ」ぐらいのことしかわからず挫折しました。ちなみに grep fread を他
のいろいろなところにもかけてみましたが、このファイル内にしか見つかりま
せんでした。
メモリへのデータの格納の様子は良く知らないのですが、fread のオンライン
日本語マニュアルにある「バイト・シーケンス」というのは、データを収める
変数のsizeであって、読み込むファイルをasciiコードなら1文字1バイトな
どと考えるのでは決してないということですね(どうも初心者には無理矢理そ
のように解釈してしまうこともできるようなマニュアルの説明だと思うのです
が)。
とすると、逆にたとえばもし以前自分がエラーしたようにdoubleなら0.0より
非常に小さい値(値による?)、intなら大きな整数値としてテキストには表
示される、それらの型に「ダイレクト」に読み込めるデータファイルのような
ものを作れるということでしょうか?(それもいわゆるバイナリーファイル?)
-----------------------------------------------------------------------
fj.lang.cの<1998Mar20.035036.3299@merope.opus.or.jp>の記事において
JST時間1998年03月20日(金)12時50分36秒頃、void@merope.opus.or.jpさんは
書きました。
| fj.testは練習用のNewsGroupではないですよ。
失礼しました。(注・本題とは関係ないです)
fj.1st-readme での説明によると Distribution:local
でテストしろとありました。
# 昔ネットワークニュースの存在を初めて知ったころ
# fj.bigginers? とかいうところに挨拶を兼ねてそう
# いう投稿があった気がします。その頃すでに廃止の
# 議論があったような気がしたのですが、本当になく
# なってしまったのでしょうか?
# (ROM以下のぶんざいですみません)
| : データの各行は 200~400×5 個位の数字から成り立っているということです。
| : すなわち行ごとに例えば Data[350] のような配列に読み込むことを考えます。
|
| どうして200~400なのに「350」なんていう宣言をするのでしょうか?
全く説明なしでした。冒頭に示した通り扱うメッシュによって配列の大きさは
事前にわかります。
| : DblData[i] = 10000 * ( CharArray2D[i][0] - '0' ) \
| : + 1000 * ( CharArray2D[i][1] - '0' ) \
| : + 100 * ( CharArray2D[i][2] - '0' ) \
| : + 10 * ( CharArray2D[i][3] - '0' ) \
| : + 1 * ( CharArray2D[i][4] - '0' );
| : のようにすれば(足し引き間違ってたらすみません)、atof系の関数は使わな
| : くてもよいのですが、これはとりあえず「可能な限り簡潔」ではないとさせて
| : 下さい。
|
| うーむそれなりに簡潔だとおもいますがね。
| 5回分をループにすれば2行で書けますし。
おっしゃる通りでした。すこぶる簡潔な表現で埋め込めますね。
#include <math.h>
for(j=0; j<5; j++)
DblData[i] = power(10,4-j) * (CharArray2D[i][j] - '0');
といったところでしょうか?
| : そこで次にダイレクトに
| : FILE *fp; /* データファイルのファイルポインタ */
| : double DblData[350]; /* 実際にデータを格納する配列 */
| : fread(DblData, 5, 350, fp);
| : などということはできないかと思って
|
| なぜ「double」なんていうものが出てくるのでしょう?
| しかもそれが「ダイレクトに」っていうのが意味不明です。
| そもそも、そのあたりの理解不足が原因のようですね。
後で読み込んだデータに対して計算を行なうので、例えばここでは
doubleに読んでいますが、intやlong intやfloatでも構いません。
文字配列に格納した数字に対して計算をdouble型などで行なうごと
く簡潔にできるような方法を自分は知りません。(たぶんそういう
意味ではなくデータのメモリへの格納云々のことをおっしゃってい
るのだと思いますが...)
| どうしても「scanf」系の関数が使いたい。それを「簡潔」だと思っている
scanfにはこだわりません。ただ、区切り文字がない時に5文字と
フィールド幅が決まっている時には、フィールド幅指定を使って
「ループを使わず、一行で文字型以外の配列に」読み込むのには
適していると思いました。配列が大きいととてつもなく長くなっ
てしまいますが。
| 話の内容からintは16bitではない環境だと予想されますが、
| 16bit程度のintだと、5桁の10進数はintに納まらないので注意が必要ですね。
sizeofで調べたところ、int,long int,float が 4byte=32bit、
doubleが 8byte でした。無論 charは 1byte です。(昔この
辺のネタで盛り上がってたようですけど突っ込まないで下さい)
------------------------------------------------------------------------
fj.lang.cの<1998Mar20.165851.12872@merope.opus.or.jp>の記事において
JST時間1998年03月21日(土)01時58分51秒頃、void@merope.opus.or.jpさんは
書きました。
| Masahiro Kondo (mako@mail.raidway.ne.jp) wrote:
| : 「長くて区切り文字のない文字列」って?
| : 区切り文字の定義があいまいですが・・・(区切りが無ければ行って観念もない
| : ですね?)
|
| あ、わたしは「行」の区切りはあって、
| 行の中の区切りがないものだと思って、それを読むコードを例示してしまったけど
| そういう意味ではなかったのか...また失敗...。
これも全く説明不足で失礼しました。冒頭で説明しましたが、
voidさんのおっしゃる通り「行の中の区切りがない」という
ことです。それと文字列ではなくて「ファイル中にテキスト
形式?(char型のバイト・シーケンス?)で表された数字の
列」とでもいえばいいのでしょうか?
あと参考までに区切りがないというのは正確ではなくて、実
際には各データの末尾は必ず '0'(ゼロ)になっています。
しかし各データの頭に出てきた時の'0'と見分けがつかず、
のちのち標高測定の精度が上がった時にこのフィールドが使
われる可能性もあるため、これを区切りとして利用すること
は勧められないと思います。
-------------------------------------------------------
また長くなってしまいましたが、こんなところです。
「素直にスペース区切りを入れたデータに変換するプログラ
ムを組め!」という御意見があるでしょうが、「ダイレクト」
に(できれば初心者にわかりやすく)読む方法があるかどうか
という興味からのみ投稿しております。
もっとも簡潔な方法(短い表現であることを含む)というのは
今まで出た以外にはやはりありえないのでしょうか?
---------------------------------------------------------------
Name : Tomoaki Chiba 千葉 智章
: Inst.Geol.Paleon.Dep.Geo.Env.Sci.Tohoku.Univ
: 東北大学理学部地圏環境科学科地質学古生物学教室4年
E-mail : chiba@dges.tohoku.ac.jp
FAX : 022-217-6634
Re: [Q]区切りなしデータを文字型でない配列に読むには?
Author: Kazuhiro Fujieda
Date: Tue, 24 Mar 1998 00:00
Date: Tue, 24 Mar 1998 00:00
37 lines
2237 bytes
2237 bytes
藤枝@JAISTです。 In article <6f67bp$djs@sakunami.gw.tohoku.ac.jp>, chiba@dges.tohoku.ac.jp(Tomoaki Chiba) wrote: > もっとも簡潔な方法(短い表現であることを含む)というのは > 今まで出た以外にはやはりありえないのでしょうか? ありえません。 > 建設省国土地理院 発行・刊行 > (財)日本地図センター 発売 > 数値地図メッシュ(標高) このデータがオープンリールのテープで売ってた頃に戦ったことがあります。 データ形式がいっちゃってるので、まずC言語で扱いやすいデータ形式に変 換した方がいいです。 たとえば、5文字×350個の標高データをshort(2bytes)×350個に変換するだ けで、ディスク使用量は半分になります。標高データは固定小数点で、数値 も限られているのでshort(2bytes)で十分です。 このように変換しておけば、次からは千葉さんの意図した通り、ダイレクト にディスクから数値データを読むことができます。もちろん、エンディアン の問題を気にしなくていい場合だけですけどね。 その他、緯度と経度からメッシュとレコードへの変換表を用意するなど、い くつか工夫することで、データサイズはさらに小さくなりますし、データを 取り出すのも簡単になります。 ちなみに昔は、データ形式に二次メッシュの概念が入ってて、今よりももっ と扱いにくかったんですよ。 ____ | AIST 北陸先端科学技術大学院大学 | HOKURIKU 情報科学研究科 落水研究室 o_/ 1990 藤枝 和宏 fujieda@jaist.ac.jp
Lab値をもとめるには?
Author: Tetsuya Watanabe
Date: Tue, 24 Mar 1998 00:00
Date: Tue, 24 Mar 1998 00:00
14 lines
1066 bytes
1066 bytes
こんにちは渡辺ともうします。
「色」のRGB値からLab値を求める方法をご存知の方
教えてください。
(コモンダイアログボックスのESLもLabのように見えるのですが..)
Cの話題としては不適切ですか?
========================================
渡辺 哲弥:東洋エンジニアリング(株)
e-mail: watanabe-t@is.toyo-eng.co.jp
watanabe-t@msn.com
========================================
Re: Lab値をもとめるには?
Author: Kusakabe Youichi
Date: Tue, 24 Mar 1998 00:00
Date: Tue, 24 Mar 1998 00:00
13 lines
1007 bytes
1007 bytes
Tetsuya Watanabe (watanabe-t@is.toyo-eng.co.jp) wrote: : $B!V?'!W$N(BRGB$BCM$+$i(BLab$BCM$r5a$a$kJ}K!$r$4B8CN$NJ}(B : $B65$($F$/$@$5$$!#(B : ($B%3%b%s%@%$%"%m%0%\%C%/%9$N(BESL$B$b(BLab$B$N$h$&$K8+$($k$N$G$9$,(B..) : C$B$NOCBj$H$7$F$OITE,@Z$G$9$+(B? $B$O$$(B $B%X(B_$B%X(B ________________________ $B%_!&!&(B $B%_(B void@merope.opus.or.jp ( $B!k(B )$B!A(B $BF|2<ItM[0l(B ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Re: [Q]$B6h@Z$j$J$7%G!<%?$rJ8;z7?$G$J$$G[Ns$KFI$`$K$O!)(B
Author: Yasuki Arasaki
Date: Wed, 01 Apr 1998 00:00
Date: Wed, 01 Apr 1998 00:00
30 lines
1756 bytes
1756 bytes
$B$$$o$:$b$,$J$G$9$,!D(B
In article <6f67bp$djs@sakunami.gw.tohoku.ac.jp>
chiba@dges.tohoku.ac.jp(Tomoaki Chiba) $B$5$s(Bwrote:
>> http://www.jmc.or.jp/250m/doc/info250.htm
>> $B!VAGD>$K%9%Z!<%96h@Z$j$rF~$l$?%G!<%?$KJQ49$9$k%W%m%0%i(B
>> $B%`$rAH$a!*!W$H$$$&8f0U8+$,$"$k$G$7$g$&$,!"!V%@%$%l%/%H!W(B
>> $B$K!J$G$-$l$P=i?4<T$K$o$+$j$d$9$/!KFI$`J}K!$,$"$k$+$I$&$+(B
>> $B$H$$$&6=L#$+$i$N$_Ej9F$7$F$*$j$^$9!#(B
>> $B$b$C$H$b4J7i$JJ}K!!JC;$$I=8=$G$"$k$3$H$r4^$`!K$H$$$&$N$O(B
>> $B:#$^$G=P$?0J30$K$O$d$O$j$"$j$($J$$$N$G$7$g$&$+!)(B
READ(LUN,'(I6,I3,320I5)') MCODE,NREC,(NHYOKO(I),I=1,320)
$B$G$$$$$s$G$9$h!#K?8@8l$G$O=i?4<T8~$1$N%3!<%I$G$9!#(B
$B$A$J$_$K!"FI$s$@8e$K(BACCESS='DIRECT'$B$G(BOPEN$B$7$?AuCV$KE,Ev$K=q$-=P$9$H(B
fread$B$G(Blong$B$NG[Ns$KD>@\FI$_9~$a$k7A$K$G$-$k$H;W$$$^$9(B
($B>/$J$/$H$b(BFreeBSD$B$G$O(B)$B!#(B
($B$3$C$A$O=i?4<T$O$"$s$^$j$d$i$J$$$_$?$$!#(B)
# FORTRAN$B$G(BC$B$G=q$-=P$7$?%G!<%?$,FI$a$J$$$H(BFORTRAN$B$,$P$+$K$5$l$k(B
$B$N$K!"(BFORTRAN$B$N%G!<%?$,(BC$B$G4JC1$KFI$a$J$$$H(B
$B!V%G!<%?7A<0$,$$$C$A$c$C$F$k!W$H$+$$$o$l$A$c$&$7!#4($$!#(B
--
$B?7:j(B%FORTRAN$B%f!<%6(B
arasaki@mns2.c.u-tokyo.ac.jp
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads