7

テキスト ファイルからすべてのコンテンツを読み込もうとしています。ここに私が書いたコードがあります。

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

#define PAGE_SIZE 1024

static char *readcontent(const char *filename)
{
    char *fcontent = NULL, c;
    int index = 0, pagenum = 1;
    FILE *fp;
    fp = fopen(filename, "r");

    if(fp) {
        while((c = getc(fp)) != EOF) {
            if(!fcontent || index == PAGE_SIZE) {
                fcontent = (char*) realloc(fcontent, PAGE_SIZE * pagenum + 1);
                ++pagenum;
            }
            fcontent[index++] = c;
        }
        fcontent[index] = '\0';
        fclose(fp);
    }
    return fcontent;
}

static void freecontent(char *content)
{
    if(content) {
        free(content);
        content = NULL;
    }
}

使い方はこれ

int main(int argc, char **argv)
{
    char *content;
    content = readcontent("filename.txt");
    printf("File content : %s\n", content);
    fflush(stdout);
    freecontent(content);
    return 0;
}

私は C に慣れていないので、このコードが完璧に見えるかどうか疑問に思っています。問題/改善点はありますか?

使用コンパイラ: GCC. ただし、このコードはクロス プラットフォームであると想定されています。

どんな助けでも大歓迎です。

編集

と を使用した更新されたコードを次に示しfreadますftell

static char *readcontent(const char *filename)
{
    char *fcontent = NULL;
    int fsize = 0;
    FILE *fp;

    fp = fopen(filename, "r");
    if(fp) {
        fseek(fp, 0, SEEK_END);
        fsize = ftell(fp);
        rewind(fp);

        fcontent = (char*) malloc(sizeof(char) * fsize);
        fread(fcontent, 1, fsize, fp);

        fclose(fp);
    }
    return fcontent;
}

この関数の相対的な複雑さはどうなるのだろうか?

4

6 に答える 6

11

関数fsize( fsize については、以下の更新を参照) とを調べてみてくださいfread。これにより、パフォーマンスが大幅に向上する可能性があります。

fsize読み込んでいるファイルのサイズを取得するために使用します。このサイズを使用して、メモリの 1 つの割り当てのみを行います。( fsize については、以下の update を参照してください。ファイルのサイズを取得して 1 つの alloc を実行するという考え方は同じです)。

freadファイルのブロック読み取りを行うために使用します。これは、ファイルの 1 文字の読み取りよりもはるかに高速です。

このようなもの:

long size = fsize(fp);
fcontent = malloc(size);
fread(fcontent, 1, size, fp);

アップデート

fsize がクロス プラットフォームであるかどうかはわかりませんが、このメソッドを使用してファイルのサイズを取得できます。

fseek(fp, 0, SEEK_END); 
size = ftell(fp);
fseek(fp, 0, SEEK_SET); 
于 2010-08-01T06:58:51.993 に答える
2

realloc線形ではなく一定の時間を償却するために、既存のサイズの 2 倍になることがよくあります。これにより、バッファーの大きさは 2 倍以下になりますが、通常は問題ありません。完了後に正しいサイズに再割り当てするオプションがあります。

しかし、さらに良いのはstat(2)、ファイル サイズを考慮して一度割り当てることです (ファイル サイズが不安定な場合は、余裕を持たせて)。

fgets(3)また、文字ごとに読み取る代わりに、またはさらに良いmmap(2)ことに、全体 (またはメモリに対して大きすぎる場合は関連するチャンク)を読み取らないのはなぜですか。

于 2010-08-01T07:04:45.563 に答える
2

おそらく遅く、確かに次のものよりも複雑です。

while((c = getc(fp)) != EOF) {
    putchar(c);
}

あなたのコードと同じことをします。

于 2010-08-01T07:21:13.870 に答える
1

ここで見られる問題の 1 つindexは、減少しない変数です。したがって、条件 if(!fcontent || index == PAGE_SIZE)は一度だけ真になります。だから私は check の index%PAGE_SIZE == 0代わりに のようにするべきだと思いますindex == PAGE_SIZE

于 2011-08-12T06:23:35.920 に答える
1

ざっと読んだだけなので、見落としがあるかもしれません。

まず、a = realloc(a, ...);間違っています。失敗した場合realloc()は を返しますがNULL、元のメモリは解放しません。に再割り当てしたためa、元のメモリが失われました (つまり、メモリ リークです)。これを行う正しい方法は次のとおりですtmp = realloc(a, ...); if (tmp) a = tmp;

次に、 を使用したファイル サイズの決定について、fseek(fp, 0, SEEK_END);これが機能する場合と機能しない場合があることに注意してください。ファイルがランダム アクセスでない場合 ( などstdin)、最初に戻って読み取ることはできません。また、バイナリ ファイルに対しては、次を実行しても意味のある結果が得fseek()られない場合があります。ftell()また、テキスト ファイルの場合、読み取れる適切な文字数が得られない場合があります。comp.lang.cFAQの質問 19.2に、このトピックに関する有用な情報がいくつかあります。

また、元のコードでは、indexに等しいときに 0 に設定しないPAGESIZEため、ファイルの長さが より大きい場合2*PAGESIZE、バッファを上書きします。

あなたのfreecontent()機能:

static void freecontent(char *content)
{
    if(content) {
        free(content);
        content = NULL;
    }
}

役に立たない。のコピーを に設定するだけcontentですNULL。次のような関数を書いた場合と同じですsetzero

void setzero(int i) { i = 0; }

はるかに良いアイデアは、メモリを自分で追跡し、必要以上に解放したり、解放したりしないことです。

C では aが他のオブジェクト ポインター型に暗黙的に変換されるため、C ではmalloc()orの戻り値をキャストしないでください。realloc()void *

それが役立つことを願っています。

于 2010-08-01T07:39:08.613 に答える
0

mmapPOSIX システム (Linux など) では、メモリ内のすべてのファイルをマップするシステム コールで同じ効果が得られます。そのファイルコピーを writeにマップするオプションがあるため、バッファを変更するとファイルが上書きされます。

できる限りシステムに任せるので、通常ははるかに効率的です。する必要はありませんrealloc

特に、読み取りのみを行っており、複数のプロセスが同時に読み取りを行っている場合、システム全体のメモリ内のコピーは 1 つだけになります。

于 2010-08-01T07:37:36.300 に答える