質問失礼いたします。
現在、ファイルから一行づつ読み込み、同じ文字列があればその行を表示するプログラムを作成しています。
fgetsで一行を取り、strstr関数で文字列の検索を行おうとしましたが、ファイルが大きいこともあり
fgetsの指定したバイト数以上に一行の文字列があった時は問題があると思い、ほかの関数を使いたいと思います。
持っているC言語の冊子を見ましたが、文字数を指定せずに読み込む関数を作ることができませんでした。
そこでfgetsのバイト数の指定を除いた関数を使いたいと思います。
初心者なので、もしそういったライブラリ関数があるならば教えていただきたいです。
また、作る場合には、どのような関数にすればいいでしょうか?
fgetsを使わずにファイルを一行ずつ読み込む方法
Re: fgetsを使わずにファイルを一行ずつ読み込む方法
>fgetsの指定したバイト数以上に一行の文字列があった時は問題があると思い
どんなイメージなのか分かりませんが、逆に文字数を指定せずに読み込む関数の方が問題があると思います…。どんなに長い行でメモリを破壊しても、自動で止まってはくれませんよ?
とはいえ動的にメモリ確保を行うのであれば、一文字読むごとにカウンタを増やしながら行末まで進み、行末で得られた長さを元にmallocで確保、一度で取得といったところでしょうか。
ところで私も似たようなモノを作ったことがあります。ログ内のデータが一致したらその行を吐くというものです。
その時は二つファイルポインタを用意しておき、片方が行の先頭を保持、もう片方で一文字ずつ検索→先頭の文字が一致したら以降一文字ずつ突き合わせ、全一致したら先頭を保持してるポインタでその行を行末まで吐く。
ということをしていました。
初歩の検索アルゴリズムしか使っていないのであまりスマートではありませんが、参考までにどうぞ。
どんなイメージなのか分かりませんが、逆に文字数を指定せずに読み込む関数の方が問題があると思います…。どんなに長い行でメモリを破壊しても、自動で止まってはくれませんよ?
とはいえ動的にメモリ確保を行うのであれば、一文字読むごとにカウンタを増やしながら行末まで進み、行末で得られた長さを元にmallocで確保、一度で取得といったところでしょうか。
ところで私も似たようなモノを作ったことがあります。ログ内のデータが一致したらその行を吐くというものです。
その時は二つファイルポインタを用意しておき、片方が行の先頭を保持、もう片方で一文字ずつ検索→先頭の文字が一致したら以降一文字ずつ突き合わせ、全一致したら先頭を保持してるポインタでその行を行末まで吐く。
ということをしていました。
初歩の検索アルゴリズムしか使っていないのであまりスマートではありませんが、参考までにどうぞ。
Re: fgetsを使わずにファイルを一行ずつ読み込む方法
fgetsを使って、最後の文字が改行になるまで繰り返して、1行分を読み込めばよいと思います。
そのたびに、reallocして格納領域を確保するのかな。
そのたびに、reallocして格納領域を確保するのかな。
non
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: fgetsを使わずにファイルを一行ずつ読み込む方法
ファイルサイズを調べて、そのサイズでメモリを確保してバイナリでfreadしたあと一行ずつ処理する手もあります。
最近の1GBぐらい平気であるメモリを有効に活用できます。
最近の1GBぐらい平気であるメモリを有効に活用できます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: fgetsを使わずにファイルを一行ずつ読み込む方法
realloc を使って書いてみました。
get_line は、読み込んだ文字数('\n' を含む)を返します。
ファイルの終わりでは 0 を返します。
バッファが拡張できなくなったら、EOF を返します。
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;
}
Re: fgetsを使わずにファイルを一行ずつ読み込む方法
皆様丁寧な解答をありがとうございます!
頂いたアドバイス等を参考に作成させていただきます!
>ゆーずぃ様
2つも例を示してくださって、ありがとうございます!
mallocはまだあまり使ったことがないのでこれを機会に挑戦してみようと思います。
>non様
解答ありがとうございます!reallocはまだ習ったことがない関数なので詳しく調べてみたいと思います!
>softya様
解答ありがとうございます!わかりやすい説明で理解することができました。検討してみます!
>かずま様
コード例まであげてくださってありがとうございます!
reallocは使ったことがない関数だったのですが、おかげでとてもイメージしやすくなりました!
是非使ってみたいと思います!
頂いたアドバイス等を参考に作成させていただきます!
>ゆーずぃ様
2つも例を示してくださって、ありがとうございます!
mallocはまだあまり使ったことがないのでこれを機会に挑戦してみようと思います。
>non様
解答ありがとうございます!reallocはまだ習ったことがない関数なので詳しく調べてみたいと思います!
>softya様
解答ありがとうございます!わかりやすい説明で理解することができました。検討してみます!
>かずま様
コード例まであげてくださってありがとうございます!
reallocは使ったことがない関数だったのですが、おかげでとてもイメージしやすくなりました!
是非使ってみたいと思います!