从文件问题中读取行

时间:2013-10-19 00:17:12

标签: c

我编写了这个简单的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 个答案:

答案 0 :(得分: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)

P.S。以你在这里的方式致电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.然后 next 调用readline()之后会返回-1。

答案 1 :(得分:1)

readline功能中,您按值current传递。因此,如果您在函数内更改bufPtr,则不会更改current之外的值。如果您想更改current的值,请参考:&current并将readline()参数更改为char **bufPTR
如果你想改变它所指向的东西,你可以按照你所做的方式通过current,但你想在第一时间改变它指向的地方

< / p>

答案 2 :(得分: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)

答案 3 :(得分: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;
}