C言語関係掲示板

過去ログ

No658 fgetsでの文字列の読み取り

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

fgetsでの文字列の読み取り
投稿者---ギャース(2003/06/10 09:24:57)


はじめましてC言語3ヶ月目(週1授業)のギャースです。

質問があります。

今、テキストファイルから1行読み取り、読み取った文字列を
色々といじるという課題をやっております。
製作が時間内に終わり、講師の先生に「これでどうですか?」
と見てもらったところ、
「これだと最大文字数以降は読み取らないよね?もし、それ以
降に使いたいデータがあった場合はどうするの?」と、言われ
そこからハマリモードです。

課題の内容は、
[名称]区切り文字[値];
というフォーマットのテキストデータを、その名称の値がいく
らか?と読み取ります。
テキストの書式として
名称、値、終了文字の;の間には、空白文字(半角スペース、
'\t')と改行'\n'を入れても大丈夫なこととします。

この読み取る部分は、strtokを絡めて使って正常に動作するの
ですが、その最大文字数以降をどうしたらいいのかわかりませ
ん。

while( fgets(cString,1024,fpread) != NULL )
{
処理
}

この読み取る部分でしっかりできればよいのですが・・・。
先輩方、どうか良いアドバイスをお願いします。

No.7235

Re:fgetsでの文字列の読み取り
投稿者---こん!(2003/06/10 10:05:18)


>名称、値、終了文字の;の間には、空白文字(半角スペース、
>'\t')と改行'\n'を入れても大丈夫なこととします。

終了文字が';'と決められていてそこまでの間に'\n'が入る可能性が有るのであ
ればfgetsを使うわけにはいけませんね。
fgetcで';'がくるまで一文字ずつ読み込みながら文字列を生成し値を抽出する
しかないのでは?


No.7236

Re:fgetsでの文字列の読み取り
投稿者---ギャース(2003/06/10 10:19:09)


レスありがとうございます!

自分もfgetcで考えたのですが、;まで読み取った後、
その次から読み直すのがよくわからないんです。
fgetcでもread全部読み取ってからなら解るのですが、
それでは元のデータが膨大な量だった場合に、超無駄
にメモリを食ってしまうのが・・・。
そこでfgetsで1行と考えたのですが・・・。

データとしては
    [名称]                                                  
         [値]
 ;  [名称]      [値];[名称]
[値]              ;[名称]
[値];

ってのもありえるのがこれまたハマリを



No.7238

Re:fgetsでの文字列の読み取り
投稿者---こん!(2003/06/10 10:25:14)


>自分もfgetcで考えたのですが、;まで読み取った後、
>その次から読み直すのがよくわからないんです。

ごめんなさい。言っている意味がよく・・・

>fgetcでもread全部読み取ってからなら解るのですが、
>それでは元のデータが膨大な量だった場合に、超無駄
>にメモリを食ってしまうのが・・・。

さらによく・・・
その解るっていう具体例のリストを上げてみては?
言葉より早い・・・
    [名称]                                                  
         [値]
 ;  [名称]      [値];[名称]
[値]              ;[名称]
[値];

こんな仕様設計があり得るって事自体そもそもの間違いのような気もするが。
(そうはいっても課題だから仕方がないのだろうね。)



No.7240

Re:fgetsでの文字列の読み取り
投稿者---ギャース(2003/06/10 10:47:43)



すみません、自分も良くわからないもので・・・。
fgetcだと通常
while( !feof(stream) )
{
	chMoji = fgetc(stream);
	fputc( chMoji , stdout );
}

見たいに書きますよね?これだと結局ファイルの最後まで
読み込むことになって、read使うのと変わらなくなってし
まいます。これを使うのであればmallocなどでメモリ確保!
って感じでしょうが、これだとメモリの無駄が多いと・・・。

で、fputcで[;]まで読み込んで、次の文字から次の[;]まで
を読み込む作業を繰り返せば良いって事を書いていただいた
と自分は理解したのですが、それがわからないのです(泣)

あと、上記のデータの例ですがあれは極端な例なんで・・・。
[名称]
  [値];
[名称]
  [値];
見たいにインデントそろえることも考えられるとの事なので。



No.7241

Re:fgetsでの文字列の読み取り
投稿者---こん!(2003/06/10 11:06:21)


while( !feof(stream) )
{
    chMoji = fgetc(stream);
    fputc( chMoji , stdout );
}
ん〜とギャースさんの仕様に’;’までの最大文字数というのは設定されていな
いのでしょうか?
int MyFgets(char* buff,int len,FILE* fp)
{
    int    i;

    buff[0] = 0;
    for( i = 0; !feof(fp) && buff[i] != ';'; i++)
    {
        buff[i] = fgetc(fp);
    }

}
こんな感じの函数作って終端までの文字列を読み込むのは駄目?
未検証の為細かい突っ込みは拒否・・・

一気にメモリー上に読み込んで整形するか或いは例の様に一文字ずつ処理するか
どちらかだと思うのですがそれはギャースさんの仕様次第です。


No.7242

Re:fgetsでの文字列の読み取り
投稿者---通りすがり(2003/06/10 11:29:31)


どもども。
fputcに持っていかれているようですが、それだと無駄にメモリとってしまう
んじゃないっすかね?
上のほうでそんなこと言ってるからね。データ量が多いと・・みたいな

たぶん、「;」までの「最大文字数」ってのは無いんじゃないかな?逆に最大
文字数を決めずにって事だと思います。つまり1行の文字数が可変長って話で
はないかと・・・。

上記のデータの形式でfgetsで名称と値が読み込めているのであればその処理
に問題は無いでしょう(タブン)。あとはfgetsで可変長の文字列をどう読むか?
ってことでしょう。最大256って決めたらそれ以上の文字列は?って先生も言っ
ている見たいですし。

No.7247

Re:fgetsでの文字列の読み取り
投稿者---物見遊山(2003/06/10 12:33:05)


横からゴメン。

>見たいに書きますよね?これだと結局ファイルの最後まで
>読み込むことになって、read使うのと変わらなくなってし
>まいます。これを使うのであればmallocなどでメモリ確保!
>って感じでしょうが、これだとメモリの無駄が多いと・・・。

入力ファイルから
名称,値
名称,値
名称,値
名称,値
というフォーマットのファイルを出力する、というのはどーでしょ?
処理速度は遅くなりそーですが。

No.7248

Re:fgetsでの文字列の読み取り
投稿者---こん!(2003/06/10 12:45:28)


ちょっと発言が前後しますが

>すみません、自分も良くわからないもので・・・。
>まいます。これを使うのであればmallocなどでメモリ確保!
って感じでしょうが、これだとメモリの無駄が多いと・・・。

この発言の仕方だと無駄は有ってもやり方は解っていて既に実現出来ている、と
受け取れますがいかがでしょう?それを見せて頂けませんか?
無駄を考える以前に正常動作を実現する方が課題としては大事だと思うのです
が?


No.7251

Re:fgetsでの文字列の読み取り
投稿者---ギャース(2003/06/10 13:23:06)


すみません。自分がわからないばっかりに皆さんにご苦労をおかけして・・・。
しかも、なんかちょいモメごとチックになり気味、キャ〜〜!!

まず仕様です。
・現状では2つの名前を判別するプログラムです(SpaceとReturn)
・名称の最大文字数は256字
・値は最大は決められてありませんがとりあえず20桁まで
・データの書式として[名称][値][;]の間には空白文字(' ''\t')と改行文字が使用可能

下のソースを見ていただければ解ると思うのですが、[;]で区別しているのではなくデリミタ区切りで読んでます。あくまで値部分で[;]が付いてたらその手前まで読み取りそれが[値]になっているだけです。

穴だらけのソースかと思いますが何か最善の方法はございますか?
なぜfgetsでやりたいかと言うと、間の空白文字がだぁ〜っとあって、最大文字数を超えた後に名称などがきた時のためです。
fgetcで改行でも[;]間ででも読み込めるのであればそれで行きたいのですが・・・。

No.7252

Re:fgetsでの文字列の読み取りのソースです
投稿者---ギャース(2003/06/10 13:24:01)


#include   <stdio.h>
#include   <string.h>
#include   <stdlib.h>
#include   "main.h"
#include   "fileopen.h"

/* #defineはヘッダーで指定してます。
#define NO_ERROR   0
#define IS_ERROR  -1
#define DELM      " \t\n"
#define FORMAT    ""
#define SPACE     "Space"
#define RUTURN    "Return"
*/

/*引数  (ファイル名,値1,値2)*/
int FileOperation(char *fpname,int *pspace,int *preturn)
{
    FILE    *fpr;                            /*使用データ読み込み用ファイルポインタ*/
    int         icntPause1,icntPause2;            /*区切り部処理カウント用変数*/
    int         icntPause3,icntPause4;            /*区切り部処理カウント用変数*/
    int         ipats,ipatr;                    /*値格納用変数*/
    char    *ptoken;                        /*トークン格納ポインタ*/
    char     cbuffer[256];                    /*トークンからの受け渡し時、一時使用配列*/
    char     cstr1[STR1_MAX];                /*1行読み込み時のデータ格納用配列*/
    char     cstr2[STR2_MAX];                /*名前格納用配列*/
    char     cstr3[STR3_MAX];                /*値格納用配列*/
    
    
    /*ファイルの中がNULLの場合のエラー処理*/
    if( ( fpr = fopen(fpname,"r") ) == NULL )    
    {
        return IS_ERROR;                                /*戻り値エラーを返す*/
    }

    /*配列の初期化*/
    strcpy(cstr2,FORMAT);
    strcpy(cstr3,FORMAT);
    
    /*読み込んだ行がNULLになるまで*/
    while( fgets(cstr1,1024,fpr) != NULL )        //ここをどうするか?
    {
        /*最初のトークンを取得*/
        ptoken = strtok(cstr1,DELM);
        
        /*トークンがNULLになるまで*/
        while( ptoken != NULL )
        {
            /*トークンの中身が[;]だけで無く、2文字以上なら*/
            if ( (strcmp(ptoken,";") != 0) && ( (int)strlen(ptoken) > 1) )
            {
                /*[;]区切りまでの文字列の格納(;が無ければ変更なし)*/
                for(icntPause1=0,icntPause2=0;icntPause1<(int)strcspn(ptoken,";");
                                                     icntPause1++,icntPause2++)
                {
                    cbuffer[icntPause2]=ptoken[icntPause1];
                }
                
                /*配列の最後にNULLを代入*/
                cbuffer[icntPause2] = '\0';
                
                /*[;]区切り以降の文字列を詰める*/
                for(icntPause3=icntPause1+1,icntPause4=0;icntPause3<=(int)strlen(ptoken);
                                                           icntPause3++,icntPause4++)
                {
                        ptoken[icntPause4] = ptoken[icntPause3];
                }
                
                /*配列の最後にNULLを代入*/
                ptoken[icntPause4] = '\0';
                
                /*文字列の中身が値か文字列か*/
                if ( (int)atoi(cbuffer) == 0 )
                {
                    strcpy(cstr2,cbuffer);
                }
                else
                {
                    strcpy(cstr3,cbuffer);
                }
            }
            
            /*cstr2とcstr3の両方に文字列が入っているなら*/
            if((int)strcmp(FORMAT,cstr2) != 0 && (int)strcmp(FORMAT,cstr3) != 0)
            {
                /*名前の比較*/
                if((int)strcmp(SPACE,cstr2) == 0)
                {
                    /*文字列の整数変換*/
                    ipats = atoi(cstr3);
                    
                    /*配列の初期化*/
                    strcpy(cstr2,FORMAT);
                    strcpy(cstr3,FORMAT);
                }
                else if((int)strcmp(RETURN,cstr2) == 0)
                {
                    /*文字列の整数変換*/
                    ipatr = atoi(cstr3);
                    
                    /*配列の初期化*/
                    strcpy(cstr2,FORMAT);
                    strcpy(cstr3,FORMAT);
                }
            }
            
            /*次のトークンを取得*/
            ptoken = strtok(NULL,DELM);
        }
    }
    
    /*パターン数の受け渡し*/
    *pspace  = ipats;
    *preturn = ipatr;
    
    /*ファイルのクローズ*/
    fclose(fpr);
    
    /*戻り値正常終了*/
    return NO_ERROR;
}


No.7256

Re:fgetsでの文字列の読み取り
投稿者---かずま(2003/06/10 14:10:37)


> fgetcだと通常
> while( !feof(stream) )
> {
>     chMoji = fgetc(stream);
>     fputc( chMoji , stdout );
> }
>
> 見たいに書きますよね?これだと結局ファイルの最後まで

いいえ、そんな風には書きません。

    while ((chMoji = fgetc(stream)) != EOF)
        fputs(chMoji, stdout);

です。

feof() は直前の入力関数(fgetc, fgets, fscanf, fread, ...) が
失敗した理由を返すものです。
これから実行する入力関数が成功するかどうかは保証しません。


No.7254

Re:fgetsでの文字列の読み取り
投稿者---かずま(2003/06/10 13:57:45)


> データとしては
>     [名称]
>          [値]
>  ;  [名称]      [値];[名称]
> [値]              ;[名称]
> [値];
> 
> ってのもありえるのがこれまたハマリを

#include <stdio.h> 

int main(void)
{ 
    char name[257];  int val;  char c;  FILE *fp = stdin;

    while (fscanf(fp, "%256s%d %c", name, &val, &c) == 3 && c == ';')
        printf("%s = %d\n", name, val);
    return 0;
}