c - 在 C 中声明字符串而不给出大小

标签 c string malloc concatenation realloc

我想将多个句子连接成一个字符串。目前我的缓冲区大小固定为 100,但我不知道要连接的句子总数,将来这个大小可能不够用。如何在不定义字符串大小的情况下定义字符串?

char buffer[100]; 
int offset = sprintf (buffer, "%d plus %d is %d", 5, 3, 5+3);
offset += sprintf (buffer + offset, " and %d minus %d is %d", 6, 3, 6-3);
offset += sprintf (buffer + offset, " even more");
printf ("[%s]",buffer);  

最佳答案

这是 C 的一个基本方面。C 从不为您自动管理动态构造的字符串 — 这始终是的责任。

以下是您可能会使用的四种不同技术的概述。您可以就其中任何不清楚的地方提出其他问题。

  1. 将您的字符串构建过程运行两次。进行一次以收集所有子字符串的长度,然后调用 malloc 以分配计算大小的缓冲区,然后进行第二次以实际构造您的字符串。

  2. 使用 malloc 分配一个较小的(或空的)初始缓冲区,然后,每次您要向其添加新的子字符串时,检查缓冲区的大小,并在必要时检查缓冲区的大小使用 realloc 让它变大。 (在这种情况下,我总是使用 三个 变量:(1) 指向缓冲区的指针,(2) 分配的缓冲区大小,(3) 当前缓冲区中的字符数。目标是始终保持 (2 ) ≥ (3).)

  3. 分配一个动态增长的“memstream”并使用fprintf 或类似的东西来“打印”它。这是一种理想的技术,尽管 memstream 不是标准的并且并非在所有平台上都受支持,而且动态分配的 memstream 更加奇特且不常见。 (自己写也是可以的,但是工作量很大。)可以使用fmemopen打开一个固定大小的memstream(虽然这不是你想要的),你可以打开 chalice ,一个使用 open_memstream 的动态分配的 memstream(这是你想要的),如果你有的话。两者都记录在 this man page 上. (此技术类似于 C++ 中的 stringstream。)

  4. “乞求宽恕胜过请求许可”的技巧。您可以分配一个您非常确定足够大的缓冲区,然后盲目地将所有子字符串填充到其中,然后在最后调用 strlen ,如果您猜错了,则字符串比您分配的缓冲区长,打印一条可怕的嘈杂错误消息并中止。这是一种直截了当且有风险的技术,而不是您会在生产程序中使用的技术。当您溢出缓冲区时,您可能会以某种方式损坏某些东西,导致程序在它有机会执行其迟来的检查和可能退出步骤之前崩溃。如果您完全使用了这种技术,那么如果您使用 malloc 分配缓冲区,它会比声明为一个普通的、固定大小的数组(无论是静态的还是本地的)。

就我个人而言,这四种方法我都用过。在世界其他地方,数字 1 和 2 几乎每个人都常用。比较它们:数字 1 简单且更容易一些,但代码复制量令人不舒服(因此,如果以后添加新字符串,可能会很脆弱);数字 2 更健壮,但显然需要您熟悉 realloc 的工作方式(如果您有任何辅助指针进入缓冲区,则此技术本身可能不够健壮每次调用 realloc 时都需要重新定位。

第 3 种技术是一种“奇特”技术:理论上几乎是理想的,但肯定更复杂并且需要一些额外的支持,因为没有像 open_memstream 这样的标准。 4 号显然是一种有风险且本质上可靠的技术,您只能在一次性或原型(prototype)代码中使用它(如果有的话),绝不会在生产中使用。

关于c - 在 C 中声明字符串而不给出大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68847561/

相关文章:

c++ - 何时量化 C sscanf 函数中忽略的模式匹配

c++ - CreateWindowEx 函数失败但 GetLastError() 返回 ERROR_SUCCESS

c - 使用 ODBC 将任何结果集格式化为 JSON

ios - 使用 Swift 提取字符串中的最后一个单词

c - 我是否将数组所有权从我的库函数传回给调用者?

C 二维数组内存分配

c - 使用 scanf 定义 malloc 数组大小并初始化

c - 如何读取以 ',."/( )""\n 分隔的字符串

以最有效的方式比较两个字符串数组

无法弄清楚如何释放我的结构