fgetsを使わずにファイルを一行ずつ読み込む方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ururu

fgetsを使わずにファイルを一行ずつ読み込む方法

#1

投稿記事 by ururu » 14年前

質問失礼いたします。
現在、ファイルから一行づつ読み込み、同じ文字列があればその行を表示するプログラムを作成しています。
fgetsで一行を取り、strstr関数で文字列の検索を行おうとしましたが、ファイルが大きいこともあり
fgetsの指定したバイト数以上に一行の文字列があった時は問題があると思い、ほかの関数を使いたいと思います。
持っているC言語の冊子を見ましたが、文字数を指定せずに読み込む関数を作ることができませんでした。

そこでfgetsのバイト数の指定を除いた関数を使いたいと思います。
初心者なので、もしそういったライブラリ関数があるならば教えていただきたいです。
また、作る場合には、どのような関数にすればいいでしょうか?

アバター
ゆーずぃ
記事: 62
登録日時: 14年前
住所: 埼玉県

Re: fgetsを使わずにファイルを一行ずつ読み込む方法

#2

投稿記事 by ゆーずぃ » 14年前

>fgetsの指定したバイト数以上に一行の文字列があった時は問題があると思い


どんなイメージなのか分かりませんが、逆に文字数を指定せずに読み込む関数の方が問題があると思います…。どんなに長い行でメモリを破壊しても、自動で止まってはくれませんよ?
とはいえ動的にメモリ確保を行うのであれば、一文字読むごとにカウンタを増やしながら行末まで進み、行末で得られた長さを元にmallocで確保、一度で取得といったところでしょうか。

ところで私も似たようなモノを作ったことがあります。ログ内のデータが一致したらその行を吐くというものです。

その時は二つファイルポインタを用意しておき、片方が行の先頭を保持、もう片方で一文字ずつ検索→先頭の文字が一致したら以降一文字ずつ突き合わせ、全一致したら先頭を保持してるポインタでその行を行末まで吐く。
ということをしていました。
初歩の検索アルゴリズムしか使っていないのであまりスマートではありませんが、参考までにどうぞ。

non
記事: 1097
登録日時: 14年前

Re: fgetsを使わずにファイルを一行ずつ読み込む方法

#3

投稿記事 by non » 14年前

fgetsを使って、最後の文字が改行になるまで繰り返して、1行分を読み込めばよいと思います。
そのたびに、reallocして格納領域を確保するのかな。
non

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: fgetsを使わずにファイルを一行ずつ読み込む方法

#4

投稿記事 by softya(ソフト屋) » 14年前

ファイルサイズを調べて、そのサイズでメモリを確保してバイナリでfreadしたあと一行ずつ処理する手もあります。
最近の1GBぐらい平気であるメモリを有効に活用できます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

かずま

Re: fgetsを使わずにファイルを一行ずつ読み込む方法

#5

投稿記事 by かずま » 14年前

realloc を使って書いてみました。
get_line は、読み込んだ文字数('\n' を含む)を返します。
ファイルの終わりでは 0 を返します。
バッファが拡張できなくなったら、EOF を返します。

コード:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char *str;
    size_t size;
    size_t capa;
} BUF;
 
int add_ch(BUF *bp, int c)
{
    if (bp->size == bp->capa) {
        char *p = realloc(bp->str, bp->capa ? bp->capa *= 2: 1024);
        if (!p) {
            free(bp->str);
            bp->str = NULL;
            bp->capa = bp->size = 0;
            return 1;  // error
        }
        bp->str = p;
    }
    bp->str[bp->size++] = c;
    return 0;  // no error
}

int get_line(BUF *bp, FILE *fp)
{
    int c;
    bp->size = 0;
    while (c = fgetc(fp), c != EOF) {
        if (add_ch(bp, c)) return EOF;
        if (c == '\n') break;
    }
    if (add_ch(bp, '\0')) return EOF;
    return bp->size - 1;  // '\0' は文字数に数えない
}

int main(int argc, char *argv[])
{
    FILE *fp;
    BUF buf = { 0 };
    if (argc != 3) return 1;
    fp = fopen(argv[2], "r");
    if (!fp) return 1;

    while (get_line(&buf, fp) > 0)
        if (strstr(buf.str, argv[1]))
            fputs(buf.str, stdout);
    fclose(fp);
    free(buf.str);
    return 0;
}

ururu

Re: fgetsを使わずにファイルを一行ずつ読み込む方法

#6

投稿記事 by ururu » 14年前

皆様丁寧な解答をありがとうございます!
頂いたアドバイス等を参考に作成させていただきます!

>ゆーずぃ様
2つも例を示してくださって、ありがとうございます!
mallocはまだあまり使ったことがないのでこれを機会に挑戦してみようと思います。

>non様
解答ありがとうございます!reallocはまだ習ったことがない関数なので詳しく調べてみたいと思います!

>softya様
解答ありがとうございます!わかりやすい説明で理解することができました。検討してみます!

>かずま様
コード例まであげてくださってありがとうございます!
reallocは使ったことがない関数だったのですが、おかげでとてもイメージしやすくなりました!
是非使ってみたいと思います!

閉鎖

“C言語何でも質問掲示板” へ戻る