0

Cのユニークなvoid関数を使用して、ファイルstdinストリームを読み取る方法を探しています。私はこの機能を使用しようとしています:

#define ENTER 10 //'\n' ASCII code

........

void read(FILE *stream, char *string) {
    char c;
    int counter = 0;

    do {
        c = fgetc(stream);
        string = realloc(string, (counter+1) * sizeof(char));
        string[counter++] = c;
    } while(c != ENTER && !feof(stream));

    string[counter-1] = '\0';
}

ただし、標準入力ストリームでのみ機能します。テキスト ファイルを使用している場合、ファイルの内容は関数の外では見えません。私はこの関数を次のように呼び出しています:

read(stdin, inputString);
read(inputFile, fileContent);

最初のケースでのみ正しく機能します。

PS: 最初に、inputString と fileContent は次のように宣言されています。

char *inputString = malloc(sizeof(char));
char *fileContent = malloc(sizeof(char));

fgetcがintを返し、char ごとの再割り当てが高価であり (ただし、必要なメモリのみを使用する必要があります)、EOF または '\n' が文字列に格納されます (ただし、後で 0 ターミネータに置き換えられます)

4

2 に答える 2

5

文字列を再割り当てしたが、新しい割り当てへのポインターを返さないため、および を誤って処理したため、どちらでも正しく動作しませんfgetc()

おそらく次のものが必要です。

void read(FILE *stream, char **string)
{
    int c;
    int counter = 0;
    int available = 0;

    while ((c = fgetc(stream)) != EOF && c != ENTER)
    {
        if (counter >= available)
        {
            int new_size = (available + 2) * 2;
            void *space = realloc(*string, new_size);
            if (space == 0)
                // Handle out of memory reporting?
                return;
            *string = space;
            available = new_size;
        }
        (*string)[counter++] = c;
    }
    (*string)[counter] = '\0';
}

そして、あなたはそれを次のように呼びます:

read(stdin, &inputString);
read(inputFile, &fileContent);

ここには多くの修正があります。改善すべき点はまだあります。

  1. 呼び出し元のコードに変更を反映できるように、ポインターをポインターに渡します。元のコードでは、realloc()呼び出しによって現在のチャンクが大きくなる可能性がある場合は回避できますが、メモリを移動する必要がある場合、移動された場所は呼び出し元の関数では使用できません。

  2. の戻り値の型fgetc()intではなくcharです。

  3. whileループよりもループを優先する必要がdo ... whileあります。コードで EOF が検出されると、格納されている文字値を配列に入れようとします。

  4. (いまだに問題があります) の初期割り当てstringはほとんど無視されます。これは、長さゼロの割り当てであるかのように扱われます。

  5. 一度に 1 文字ずつ格納されるスペースを増やしますが、これは非効率的です。改訂されたコードでは、使用可能なスペースが毎回約 2 倍になります。また、終端のヌル バイトに十分なスペースを割り当てます。

  6. Unfixed: 名前read()は標準 C では予約されていませんが、POSIX 関数を使用すると事実上予約されます。

エラーを報告する方法は (まだ) ありません。私は実際には次のような関数を好むでしょう:

char *read_line(FILE *stream)
{
    int c;
    int counter = 0;
    int available = 2;
    char *string = malloc(available);

    if (string == 0)
        return string;

    while ((c = fgetc(stream)) != EOF && c != ENTER)
    {
        if (counter >= available)
        {
            int new_size = (available + 2) * 2;
            void *space = realloc(string, new_size);
            if (space == 0)
            {
                free(string);
                return 0;
            }
            string = space;
            available = new_size;
        }
        string[counter++] = c;
    }
    string[counter] = '\0';
    return string;
}

getline() POSIX関数も調べる必要があります。

于 2013-08-31T05:57:00.497 に答える
0

さて、あなたの機能はうまくいきました。次のコードを確認してください。

#include <stdio.h>
#define ENTER 10 //'\n' ASCII code

void read(FILE *stream, char **string) {
char c;
int counter = 0;
do {
    c = fgetc(stream);
    *string = realloc(*string, (counter+1) * sizeof(char));
    (*string)[counter++] = c;
} while(c != ENTER && !feof(stream));

(*string)[counter-1] = '\0';
}
int main()
{
char *p = malloc(1);
read(fopen("sam.txt", "r"), &p);
printf("%s\n", p);
return 0;
}

の内容sam.txtが正確に印刷されました。file nameの代わりにを渡していたと思いますfile pointer to the file。また、 realloc on を適用するには、ポインターの参照を渡す必要がありますp。お役に立てれば。

于 2013-08-31T06:10:51.213 に答える