从文件中读取特定行

时间:2014-05-11 19:20:58

标签: c file cstring

我正在尝试使用以下代码从文件中读取特定行。

char *getlinenum(char *filename, int lnum)
{
    FILE *f;
    int i;
    char *linebuf = NULL, *tmp = NULL;
    if ((f = fopen(filename, "r")) != NULL)
    {
        linebuf = (char *)malloc(2048);
        memset(linebuf, 0, 2048);
        for (i = 0; i < lnum; i++)
        {
            if (fscanf(f, "%[^\n]\n", linebuf) == EOF)
            {
                free(linebuf);
                fclose(f);
                printf("Returning NULL\n");
                return NULL;
            }
        }
        //tmp = strdup(linebuf);
        //free(linebuf);
        fclose(f);
        return linebuf;
    }
    return NULL;
}

无论如何,这总是只返回一个空(零)字符串。您看到的任何问题?这是测试文件:

/home/mainframe/b
/home/mainframe/dead.letter
/home/mainframe/.bash_history
/home/mainframe/a
/home/mainframe/f
/home/mainframe/e
/home/mainframe/c
/home/mainframe/g
/home/mainframe/.ssh/authorized_keys
/home/mainframe/.ssh
/home/mainframe/d

我真的不明白最终会出现零字符串(不是空指针)。

2 个答案:

答案 0 :(得分:1)

这段代码对我有用(除了删除uncesessary tmp变量之外没有任何变化)

一个问题是如果传递0,则for循环永远不会进入。只需将其更改为&lt; =和/或在开头添加另一个if语句:

if( lnum <= 0 ) 
  return NULL;

抓住这个问题。

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

char *getlinenum(char *filename, int lnum)
{
    FILE *f;
    int i;
    char *linebuf = NULL;

    if( lnum <= 0 ) 
      return NULL;

    if ((f = fopen(filename, "r")) != NULL)
    {
        linebuf = (char *)malloc(2048);
        memset(linebuf, 0, 2048);
        for (i = 0; i <= lnum; i++)
        {
            if (fscanf(f, "%[^\n]\n", linebuf) == EOF)
            {
                free(linebuf);
                fclose(f);
                printf("Returning NULL\n");
                return NULL;
            }
        }
        free(linebuf);
        fclose(f);
        return linebuf;
    }
    return NULL;
}

int main()
{
   printf("%s\n", getlinenum("input.txt", 2));
   return 0;
}

输出:

/home/mainframe/dead.letter

答案 1 :(得分:1)

一个相当明显的问题是,如果有一条长于2048的行,这段代码会溢出缓冲区。

另一个问题是你的fscanf字符串会跳过空行(文件的第一行除外)。我不确定这是否是故意的。你在字符串末尾的\n匹配器意味着匹配所有空格,直到下一个非空格,即使该空格包含多个换行符。

要解决该问题,您可以删除该\n,并在每个fgetc()后执行fscanf以使用一个换行符。

要修复缓冲区溢出,我建议跳过你想要的行而不存储任何内容,然后使用fgets来获取你感兴趣的行。例如(这里我也考虑了清理代码):

if (lnum < 1 || (f = fopen(filename, "r")) == NULL)
    return NULL;

char *buffer = NULL;

for ( ; lnum > 1; --lnum )
{
     if ( fscanf(f, "%*[^\n]") == EOF || fgetc(f) == EOF ) 
          break;
}

if ( lnum == 1 )
{
// or use the POSIX getline() function or similar, to avoid any size limitation and
// avoid the mucking around with fgets and \n
   buffer = calloc(1, 2048);

    if ( ! fgets(buffer, 2048, f) )
    { 
        free(buffer); 
        buffer = NULL;
    }
    else if ( buffer[0] && buffer[strlen(buffer)-1] == '\n' )
       buffer[strlen(buffer)-1] = 0;
}

fclose(f);
return buffer;

此外,使用unsigned long long line_num可以让您阅读更多内容!