【问题标题】:How to simplify this readLine() function?如何简化这个 readLine() 函数?
【发布时间】:2019-10-10 12:20:44
【问题描述】:

我有这个函数,它读取一些 .txt 文件的第一行并返回该行供我使用。我不知道这条线有多长,所以我不能有恒定大小的缓冲区。 我的问题是我不能使用这个功能,因为它不是我的代码,它会被认为是作弊(我有我的考试)。

我一直在考虑数组的可变长度,但它是邪恶的,因为它对我说,我可以在某个地方扫描整行,但我不确定在这种情况下我该怎么做(我需要返回该行)

char* readLine(FILE *line) { 
    char individualChar;
    int pos = 0;
    int size = 16;
    char *buffer = (char *)malloc(size);

    while ((individualChar = fgetc(line)) != EOF && individualChar != '\n'){
        if (pos + 1 == size){
            size *= 2;
            char *tmp = (char *)realloc(buffer, size);
            if (!tmp){
                free(buffer);
                fprintf(stderr, "Realloc failed");
                return 0;
            }
            buffer = tmp;
        }
        buffer[pos] = individualChar;
        pos++;
    }

    buffer[pos] = '\0';
    return buffer;
}

【问题讨论】:

  • 这是正确的做法。任何使用数组的解决方案都会受到数组大小的限制。
  • 您可以调用fgets() 来读取更大的块,而不是调用fgetc()。检查结果的最后一个字符是否为换行符。如果不是,请重新分配缓冲区并再次调用fgets() 以获取下一个块。不断重复,直到你得到一个以换行符结尾的块。
  • 我不确定您在寻找什么样的答案。您不想通过复制别人的代码来作弊,但我们还能回答什么?
  • 是的,VLA 是邪恶的。使用 realloc 是理想的方法,但使用固定数组并仅记录限制(“该程序只能处理少于 4k 字节的文本行”)通常是可以接受的。
  • Barmar 我想知道如何以不同的方式做到这一点。就像“你可以使用函数 something() 来得到这个并且......”不知道如何更好地解释它。 xing .. 这个 int 不等于 char 的 ascii 值并被转换了吗?

标签: c file text readline simplify


【解决方案1】:

你可以有一个更简单的方法:

  1. 计算第一行的大小
  2. 一步分配所需内存
  3. 将行读入分配的内存

这段代码不是最优的,因为它读取文件两次,但我认为 你会更容易适应:

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

char *readline(FILE *f)
{
    size_t size = 0;
    char *ret = NULL;
    long pos = ftell(f);

    /* find line size */
    int c = fgetc(f);
    while (c != EOF && c != '\n')
    {
        c = fgetc(f);
        ++size;
    }

    if (size)
    {
        /* allocate mem */
        ret = malloc(size + 1);

        /* rewind file */
        fseek(f, SEEK_SET, pos);

        /* read data */
        fread(ret, 1, size, f);

        /* add string limiter */
        ret[size] = 0;
    }
    return ret;
}

警告

此代码不完整,因为它没有测试:

  • f 不是NULL
  • mallocfread的返回值

【讨论】:

  • 读第二行会不会有问题?我将倒带整个文件,而不仅仅是实际行。还是我错了?
  • rewind() 会出现问题,建议改用fseek() 并从当前位置返回长度(在调用malloc() 时使用)以退回到开头当前行
  • 并非所有输入都是可搜索的,但即使是不可搜索的输入(例如终端!),您也应该能够读取该行。将人类类型的所有东西都做两次只是为了计算第一次有多长时间是不合情理的!这是与此函数是“readFirstLine()”而不是readLine()这一事实不同的问题。
  • fprintf()fscanf()fgets() 都不会检查文件指针参数是否为空。那个测试是没有必要的。测试来自malloc() 的空指针是必要的。
  • "此代码不完整,因为它没有测试:" --> 也没有测试 pos != -1fseek()
【解决方案2】:

在这里发布很多代码并不好,因为 OP 有

被认为是作弊(我有考试),因为它不是我的代码。

所以一些提示


我不知道这条线有多长,所以我不能有恒定大小的缓冲区。

防御性编程假定一个合理的、理智的上限来防止黑客攻击。 IAC,读取文本文件会产生环境限制

环境限制
实现应支持行包含至少 254 个字符的文本文件,包括终止换行符。宏 BUFSIZ 的值应至少为 256。C11 §7.21.2 7

采用这种方法:

#include <stdio.h>
#define SANE_BOUND (BUFSIZ+1)

char* readLine(FILE *line) { 
  char buffer[SANE_BOUND];
  if (fgets(buffer, sizeof buffer, line) == NULL) {
    return NULL;
  }
  return strdup(buffer);
}

如何简化这个readLine()函数?

需要明确的是,您不想复制的代码有问题

更正

// char is insufficient to distinguish the 257 different results from fgetc()
// char individualChar;
int individualChar;

// Use size_t for sizing, `int` may be too small
size_t pos = 0;
size_t size = 16;

如果第一个fgetc()调用返回EOF或以后调用返回EOF由于罕见的输入错误,函数应该返回NULL

放下演员表,不需要。

//char *buffer = (char *)malloc(size);
//char *tmp = (char *)realloc(buffer, size);
char *buffer = malloc(size);
char *tmp = realloc(buffer, size);

为什么检查不完整?

代码有if (!tmp){,但没有事先检查if (!buffer){

轻微

// Use \n and stay case correct
// fprintf(stderr, "Realloc failed");
fprintf(stderr, "realloc() failed\n");

迂腐

size *= 2; 可能会溢出。你想有多安全?

设计

我会调整大小最后一个realloc()

我会重新设计以将读取的大小和分配的内存都传达给调用者。文本文件 lines 不常见地可能包含 null 字符,并且只返回一个 string 指针,不传达一些被读取的信息。也适用于这个case


分配readLine() 将没有OP 发布的代码那么简单。

【讨论】:

    猜你喜欢
    • 2014-07-20
    • 2020-12-31
    • 2020-10-20
    • 2015-05-30
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 2011-06-21
    相关资源
    最近更新 更多