1

この単純なreadline関数を作成しました。各行の長さを返すことができますが、割り当てられた buffer へのポインターは返しません。別の問題は、最後の行が無視されることです (それは返されません):

FILE *passFile = NULL;
char *current = NULL;
size_t len = 0;
passFile = fopen("pass.txt", "r");
while(readline(passFile, &current, &len) != -1) {
    printf("%s\n", current); // SEGMENTAION FAULT
    printf("%d\n", len);
    free(current);
    current = NULL;
}

ssize_t
readline(FILE *file, char **bufPtr, size_t *len)
{
    char c, *buf = NULL;
    size_t n = 0;
    buf = (char*)malloc(sizeof(char));
    while((c = fgetc(file)) != '\n' && (c != EOF)) {
        buf[n] = c;
        ++n;
        buf = realloc(buf, n + 1);
    }

    buf[n] = '\0';
    *bufPtr = buf;
    *len = n;
    if(c == EOF)    // reach end of file
        return -1;

    return 0;
}
4

4 に答える 4

2

readline()関数が割り当てられたメモリへのポインターを返していません。あなたの呼び出しでcurrentは、設定されていないため、ポインターが無効になり、エラーが発生します。

C では、関数は「値による呼び出し」です。内部readline()bufPtrは、渡されたもののコピーがありますreadline()。への代入bufPtrは、ローカル コピーを上書きするだけで、呼び出し元のコードが認識できる値を返しません。

擬似コード:

TYPE a;

define function foo(TYPE x)
{
    x = new_value;
}

foo(a);  // does not change a

これは のローカル コピーを変更するだけでx、値を返しません。ポインターを使用するように変更します...関数は引き続きコピーを取得しますが、ポインターのコピーになり、そのポインター値を使用して元の変数を見つけることができます。擬似コード:

TYPE a;

define function foo(TYPE *px)
{
    *px = new_value;
}

foo(&a);  // does change a

ここで、関数を変更するには:

ssize_t
readline(FILE *file, char **pbufPtr, size_t *len)
{
    // ...deleted...
    buf[n] = '\0';
    *pbufPtr = buf;
    // ...deleted...
}

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

while(readline(passFile, &current, &len) != -1)

PSここで行う方法を呼び出すrealloc()のは良い考えではありません。これは非常に遅い関数である可能性があり、65 文字の入力文字列の場合、65 回呼び出すことになります。最初のファイル入力に内部バッファーを使用し、次に使用malloc()して適切なサイズの文字列を割り当て、その文字列をバッファーにコピーすることをお勧めします。文字列が長すぎて一度に内部バッファーに収まらない場合は、 を使用malloc()して、内部バッファーにある文字列の一部をコピーするのに十分な大きさの場所を取得してから、内部バッファーを使用してさらに多くの文字列をコピーします。 、必要に応じ呼び出しrealloc()ます。基本的に、サイズ N の内部バッファを用意し、文字列を一度に N 文字のチャンクでコピーして、呼び出しの数を最小限に抑えることをお勧めします。realloc()任意の長さの入力文字列を引き続き許可します。

編集:最後の行の問題は、返す行があるにもかかわらず、ファイルの終わりに到達したときに -1 を返すことです。

c == EOF の場合にのみ -1 を返すようにコードを変更してn == 0、EOF で終わる最終行が正しく返されるようにします。

また、関数をreadline()使用してがファイルの終わりにあるかどうかを確認し、そうであれば、を呼び出さずに -1 を返す必要があります。feof()filemalloc()

基本的に、-1 を返すときに を呼び出したくありませんmalloc()。また、呼び出しmalloc()てデータをコピーしたときに、-1 を返したくありません! -1 は、「ファイルの終わりに達したため、何も得られなかった」ことを意味するはずです。ファイルの終わりに到達する前に何かを取得した場合、それは -1 ではなく、0 です。その後の次の呼び出しreadline()は -1 を返します。

于 2013-10-19T00:20:02.100 に答える
1

関数では、値readline渡しcurrentします。したがって、関数の内部を変更しても、外部bufPtrの値は変更されません。参照渡しcurrentの値を変更したい場合は、パラメータを に変更します。それが指している何かを変更したい場合は、あなたが行った方法を 渡すことができますが、最初にそれが指している場所を変更したい.current&currentreadline()char **bufPTR
current

于 2013-10-19T00:26:39.310 に答える
0

今では動作します:

ssize_t
readline(FILE *file, char **bufPtr, size_t *len)
{
    if(feof(file))  // reach end of file
        return -1;

    char c, *buf = NULL;
    size_t n = 0, portion = CHUNK;
    buf = (char*)malloc(sizeof(char) * CHUNK);
    while((c = fgetc(file)) != '\n' && (c != EOF)) {
        buf[n] = c;
        ++n;
        if(n == portion) {
            buf = realloc(buf, CHUNK + n);
            portion += n;
        }
    }

    buf[n] = '\0';
    *bufPtr = buf;
    *len = n;

    return 0;
}
于 2013-11-06T21:04:21.993 に答える