我想用一个字符串连接多个句子。目前我的缓冲区是固定大小的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); 发布于 2021-08-19 12:28:17
这是C. C的一个基本方面,它从不为您自动管理动态构造的字符串--这始终是您的责任。
这里概述了您可能使用的四种不同技术。你可以就这些问题中的任何一个问一些不清楚的问题。
malloc分配计算大小的缓冲区,然后再进行第二次传递,以实际构造字符串。malloc分配一个小的(或空的)初始缓冲区,然后每次要向它追加一个新的子字符串时,检查缓冲区的大小,如果必要的话,使用realloc将其放大。(在这种情况下,我总是使用三个变量:(1)指向缓冲区的指针,(2)分配的缓冲区大小,(3)当前缓冲区中的字符数。目标是始终保持(2)≥(3))。fprintf等来”打印“到它。这是一种理想的技术,尽管并不是所有平台都支持memstreams的标准,而动态分配memstreams则更有异国情调,也更不常见。(你可以自己写,但这是一项很大的工作。)您可以使用fmemopen打开一个固定大小的内存流(尽管这不是您想要的),如果您有它,您也可以使用open_memstream打开圣杯,这是一个动态分配的内存流(这就是您想要的)。这两者都被记录在这个手册页上。(这一技术类似于stringstream in C++)。strlen,如果您猜错了,并且字符串比您分配的缓冲区长,则打印一条可怕的嘈杂错误消息并中止。这是一种生硬和危险的技术,而不是你在生产程序中使用的技术。当缓冲区溢出时,可能会导致程序在执行迟来的检查和退出步骤之前崩溃。如果您使用此技术,如果使用malloc分配缓冲区,将比将其声明为普通的、固定大小的数组(无论是静态的还是本地的)“安全得多”(也就是说,在检查之前过早崩溃的可能性要小得多)。就我个人而言,我用了这四个。在世界其他地方,数字1和2几乎每个人都在使用。比较它们:数字1很简单,也比较容易一些,但代码复制量很大(因此如果稍后添加新字符串,可能会很脆弱);第2条更健壮,但显然需要您对realloc的工作方式感到满意(如果每次调用realloc时都需要对缓冲区中的任何辅助指针进行深思熟虑的重新定位,那么这种技术本身可能就不那么健壮)。
第3条是一种“奇异”的技术:理论上几乎是理想的,但肯定更复杂,需要一些额外的支持,因为没有任何东西像open_memstream是标准的。第四条显然是一种风险很大且本质上不可靠的技术,如果有的话,你只会在一次性或原型代码中使用,永远不会在生产中使用。
发布于 2021-08-19 12:38:59
您可以使用带有NULL的snprintf函数作为第一个参数,对于第二个参数使用0,获得格式化字符串的大小。然后,您可以动态地分配空间,并再次调用snprintf来实际构建字符串。
char *buffer = NULL;
int len, offset = 0;
len = snprintf (NULL, 0, "%d plus %d is %d", 5, 3, 5+3);
buffer = realloc(buffer, offset + len + 1);
offset = sprintf (buffer + offset, "%d plus %d is %d", 5, 3, 5+3);
len = snprintf (NULL, 0, " and %d minus %d is %d", 6, 3, 6-3);
buffer = realloc(buffer, offset + len + 1);
offset += sprintf (buffer + offset, " and %d minus %d is %d", 6, 3, 6-3);
len = snprintf (NULL, 0, " even more");
buffer = realloc(buffer, offset + len + 1);
offset += sprintf (buffer + offset, " even more");
printf ("[%s]",buffer);请注意,此实现省略了对realloc和snprintf的检查,以保证简洁性。它还重复格式字符串和参数。以下功能解决了这些缺陷:
int append_buffer(char **buffer, int *offset, const char *format, ...)
{
va_list args;
int len;
va_start(args, format);
len = vsnprintf(NULL, 0, format, args);
if (len < 0) {
perror("vsnprintf failed");
return 0;
}
va_end(args);
char *tmp = realloc(*buffer, *offset + len + 1);
if (!tmp) {
perror("realloc failed");
return 0;
}
*buffer = tmp;
va_start(args, format);
*offset = vsprintf(*buffer + *offset, format, args);
if (len < 0) {
perror("vsnprintf failed");
return 0;
}
va_end(args);
return 1;
}你可以这样称呼它:
char *buffer = NULL;
int offset = 0;
int rval;
rval = append_buffer(&buffer, &offset, "%d plus %d is %d", 5, 3, 5+3);
if (!rval) return 1;
rval = append_buffer(&buffer, &offset, " and %d minus %d is %d", 6, 3, 6-3);
if (!rval) return 1;
rval = append_buffer(&buffer, &offset, " even more");
if (!rval) return 1;
printf ("[%s]",buffer);
free(buffer);https://stackoverflow.com/questions/68847561
复制相似问题