1

我写了这个简单的readline函数,它可以返回每一行的长度,但它不返回指向已分配缓冲区的指针。另一个问题是最后一行被忽略(它不返回它):

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 n == 0时返回 -1 ,因此将正确返回以 EOF 结尾的最后一行。

您还应该readline()使用该feof()函数检查是否file在文件末尾,如果是,则返回 -1 而不调用malloc().

基本上,当您返回 -1 时,您不想调用malloc(),当您调用malloc()并将数据复制到其中时,您不想返回 -1!-1 应该意味着“你什么都没有,因为我们到达了文件末尾”。如果在我们到达文件结尾之前你得到了一些东西,那不是-1,而是 0。然后下一次调用readline()after 将返回 -1。

于 2013-10-19T00:20:02.100 回答
1

在您的readline函数中,您按值传递current。因此,如果您bufPtr在函数内部进行更改,则不会更改current外部的值。如果要更改current通过引用传递它的值:&current并将readline()参数更改为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 回答
0

用这个替换你的readline函数

char*   readline(FILE *file, 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 NULL;

    return buf;
}

然后用这个main替换这一行while(readline(passFile, current, &len) != -1)while((current = readline(passFile, &len) != NULL)

于 2013-10-19T00:27:23.193 回答