我需要为作业做些什么:
我遇到的问题是我需要在名称中读取任意长字符串,而且我不知道如何存储该字符串而不浪费内存(或写入未分配的内存)。
修改
我的第一个想法是分配一个1字节(字符)内存块,然后调用realloc()如果需要更多字节,但这似乎不是很有效。或者,如果数组已满,我可以将数组加倍,然后在最后将字符复制到一个具有确切大小的新内存块中。
答案 0 :(得分:5)
不要担心浪费100或1000字节,这可能对所有名称都足够长。 我可能只是把你正在阅读的缓冲区放在堆栈中。
执行担心写入缓冲区的末尾。即缓冲区溢出。计划,以防止这种情况!
当您将名称存储到结构中时,可以使用malloc缓冲区来存储名称所需的确切长度(不要忘记为null终止符添加额外的字节)。
但如果你真的必须存储任何长度的名字,那么你可以用realloc来做。 即分配一个大小为50字节的malloc的缓冲区。
然后当你需要更多空间时,使用realloc来增加它的长度。增加50个字节块的长度,并用int来跟踪它的大小,以便您知道何时需要再次增长它。在某些时候,你必须决定缓冲区的长度,因为它无法无限增长。
答案 1 :(得分:2)
你可以逐个字符地读取字符串,直到你找到结束,然后回到开头,分配一个合适大小的缓冲区,并重新读入它,但除非你在一个很小的嵌入式系统上这是可能很傻。首先,fgetc,fread等函数无论如何都会在O / S中创建缓冲区。
你可以分配一个足够大的临时缓冲区,使用长度有限的读取(为了安全),然后分配一个精确大小的缓冲区来复制它。您可能希望在堆栈上而不是通过malloc分配临时缓冲区,除非您认为它可能超出可用堆栈空间。
如果您正在为一个小型系统编写单线程代码,您可以在启动或静态时分配暂存缓冲区,并将其重新用于多种用途 - 但要非常小心,您的使用不能重叠!
鉴于大多数系统的实现复杂性,除非你真正研究工作原理,否则完全有可能编写内存优化代码,实际上需要更多内存而不是简单的方法。变量初始化可能是另一个令人惊讶的浪费。
答案 2 :(得分:2)
我的建议是分配一个足够大小的缓冲区:
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
,但它会使代码变得比必要的复杂得多,并且它会引入可能出现错误的位置 - NULL指针,数组索引越界错误等。在大多数实际案例中,分配足以满足您的数据需求以及少量呼吸空间的情况。如果您发现很多情况下数据超出了缓冲区的大小,请调整缓冲区以适应它 - 这就是调试和测试用例的用途。