假设我们想将const char * s [0],s [1],... s [n-1]连接到C中的一个long char out []中。
形式上(为简单起见,忽略缓冲区溢出):
void concatManyStrings(char out[], const char *s[], size_t n);
当然,这是一项微不足道的任务:从指针开始并为每个字符前进, 在循环输入字符串时。
另一种方法(仍然是线性时间)是保持指向结尾的指针,
每个s [i]做:
{ strcpy(endp, s[i]); endp += strlen(s[i]); }
但是,如果有一个标准的CRT函数知道如何strcpy()
,则代码会更清晰
并返回复制的字符数(或等效地,复制后指向下一个字符的指针)。
我能想到的唯一CRT功能就是sprintf()
,但显然不是很近
与返回计数的简单strcpy()
一样高效。
是否有这样的功能我不见了?
答案 0 :(得分:2)
strlcpy()
和strlcat()
是非标准的,但如果您碰巧拥有它们,则可以将它们用于此目的。它们都返回允许您确定复制字符串的 end 的结果,这与strcpy()
和strcat()
不同,后者(有点无用)返回指向目标起点的指针。 / p>
答案 1 :(得分:1)
你不能忽视缓冲区溢出;这是网络世界崩溃的主要方式之一。
鉴于显示的数据结构,您可以执行的操作有限。如果数据结构包含传递给函数的数据中每个字符串的长度,那么您可以做更多的事情。但是,在此之前,您必须确定每个字符串的长度(并提供输出缓冲区的长度),然后安排安全地复制字符串。因为在您复制时您将知道字符串的长度,您可以使用memmove()
或memcpy()
来移动数据,并且您知道长度以便您可以调整指针:
int concatManyStrings(char *buffer, size_t buflen, const char **data, size_t nitems)
{
assert(buflen > 0);
char *dst = buffer;
char *end = buffer + buflen - 1;
for (size_t i = 0; i < nitems; i++)
{
size_t len = strlen(data[i]);
if (dst + len >= end)
return -1;
memmove(dst, data[i], len);
dst += len;
}
*dst = '\0';
return 0;
}
这会扫描每个字符串两次 - 一次是长度,一次是复制。但是,由于其空填充行为(在此上下文中是恶魔般的),您无法使用strncpy()
;事实上,它不保证空终止不会是一个问题。在知道长度是安全的之前,您不能使用strcpy()
,这需要strlen()
。如果数据不是指向字符串的简单指针数组,而是包含字符串长度和指针的结构数组,则可以避免使用strlen()
。谨慎使用strcat()
或strncat()
可能是可行的;主要的注意事项是避免二次行为(Schlemiel算法),这可以通过确保确定每个添加的字符串的结尾来完成。在strncat()
的情况下,要非常小心size参数;它与strncpy()
的大小不同。你仍然可能需要使用strlen()
,因为标准函数不报告它们放置最后一个字符的字符串结尾 - 这比返回指向目标字符串的第一个字符的指针要有用得多
我知道没有标准功能可以做到这一点。
答案 2 :(得分:0)
使用snprintf
,对于任何有关汇编字符串的问题,基本上总是正确答案:
snprintf(buf, buflen, "%s%s%s", str1, str2, str3);
不幸的是,这不适用于“任意n
”作为输入字符串计数;为此,只需编写自己的循环...