代码之家  ›  专栏  ›  技术社区  ›  helpermethod

fgetc():读取和存储未知长度的字符串

c
  •  3
  • helpermethod  · 技术社区  · 14 年前

    我需要做的是:

    • 打开文件(使用fopen())
    • 读取学生的姓名(使用fgetc())
    • 将该名称存储在结构的某个部分中

    我遇到的问题是,我需要将任意长字符串读入名称,我不知道如何在不浪费内存(或写入未分配的内存)的情况下存储该字符串。

    编辑

    我的第一个想法是分配一个1字节(char)内存块,如果需要更多字节,则调用realloc(),但这似乎不是很有效。或者,如果数组已满,我可以将其加倍,然后在最后将字符复制到一个大小相同的新内存块中。

    3 回复  |  直到 14 年前
        1
  •  5
  •   hookenz    14 年前

    不要 担心会浪费100或1000个字节,这些字节对于所有的名字来说都足够长了。 我可能会把你读到的缓冲区放在堆栈上。

    担心在缓冲区末尾写入。即缓冲区溢出。防止这种情况的程序!

    当您将名称存储到结构中时,可以使用malloc缓冲区来存储所需的确切长度的名称(不要忘记为空终止符添加额外的字节)。

    但如果您真的必须存储任何长度的名称,那么您可以使用realloc来实现。 也就是说,分配一个malloc大小为50字节的缓冲区。

    当你需要更多的空间时,使用realloc来增加它的长度。以50字节为单位增加块的长度,并用一个int来跟踪它的大小,以便知道何时需要再次增加它。在某个时候,你必须决定缓冲区的长度,因为它不能无限期地增长。

        2
  •  2
  •   Chris Stratton    14 年前

    你可以一个字符一个字符地读字符串,直到找到结尾,然后倒回开头,分配一个大小合适的缓冲区,然后重新读到结尾,但是除非你在一个小型的嵌入式系统上,否则这可能是愚蠢的。首先,fgetc、fread等函数无论如何都会在O/S中创建缓冲区。

    您可以分配一个足够大的临时缓冲区,对其使用长度限制读取(为了安全起见),然后分配一个精确大小的缓冲区将其复制到其中。您可能希望在堆栈上而不是通过malloc分配临时缓冲区,除非您认为它可能超出可用的堆栈空间。

    如果您正在为一个小系统编写单线程代码,您可以在启动时或静态地分配一个临时缓冲区,并将其重新用于许多目的-但要非常小心,您的使用不能重叠!

    考虑到大多数系统的实现复杂性,除非你真正研究事物是如何工作的,否则完全有可能编写内存优化的代码,而不是简单地做事情。变量初始化可能是另一个令人惊讶的浪费。

        3
  •  2
  •   Will    14 年前

    我的建议是分配一个足够大的缓冲区:

    char name_buffer [ 80 ];
    

    一般来说,大多数名字(至少是常见的英文名字)的大小将小于80个字符。如果你觉得你可能需要更多的空间,那就一定要分配更多的空间。

    保留一个计数器变量,以了解已读入缓冲区的字符数:

    int chars_read = 0; /* most compilers will init to 0 for you, but always good to be explicit */
    

    此时,逐字阅读 fgetc() 直到到达文件结束标记或读取80个字符(实际上是79个字符,因为您需要空终止符的空间)。将读取的每个字符存储到缓冲区中,使计数器变量递增。

    while ( ( chars_read < 80 ) && ( !feof( stdin ) ) ) {
      name_buffer [ chars_read ] = fgetc ( stdin );
      chars_read++;
    }
    if ( chars_read < 80 )
      name_buffer [ chars_read ] = '\0'; /* terminating null character */
    

    我想你是在读 stdin . 一个更完整的示例还将检查错误,验证从流中读取的字符对于某人的姓名(例如,没有数字)是否有效等。如果尝试读取的数据多于分配空间的数据,请将错误消息打印到控制台。

    我理解希望尽可能保持小的缓冲区,并且只分配您需要的内容,但是学习如何编程的一部分是理解代码/数据大小、效率和代码可读性方面的权衡。你可以 malloc realloc ,但它使代码比必需的复杂得多,并且它引入了可能出现错误的位置-空指针、数组索引越界错误等。对于大多数实际情况,分配应该足以满足您的数据需求的内容以及少量的喘息空间。如果发现遇到很多数据超过缓冲区大小的情况,请调整缓冲区以适应它—这就是调试和测试用例的目的。