1

假设我们想在 C 中将 const char *s[0], s[1], ... s[n-1] 连接成一个 long char out[]。

形式上(为简单起见,忽略缓冲区溢出):

void concatManyStrings(char out[], const char *s[], size_t n);

当然,这是一项微不足道的任务:从指向 out 的指针开始并为每个 char 推进它,
同时循环输入字符串。

另一种方法(仍然是线性时间)是保持一个指向末尾的指针,
并且每个 s[i] 都这样做:

{ strcpy(endp, s[i]); endp += strlen(s[i]); }

但是,如果有一个标准的 CRT 函数知道如何strcpy()
并返回复制的字符数(或等效地,指向复制后的下一个字符的指针),则代码会更清晰。

我能想到的唯一 CRT 函数就是sprintf(),但它显然不如返回计数
的简单函数那么有效。strcpy()

有没有我缺少的功能?

4

3 回答 3

2

strlcpy()并且strlcat()是非标准的,不幸的是,但如果你碰巧拥有它们,你可以使用它们。它们都返回结果,让您确定复制的字符串的结尾,不同的strcpy()strcat()(有点无用)返回指向目标开头的指针。

于 2011-08-25T19:54:55.587 回答
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()谨慎行事,使用or可能是可行的strncat();主要的注意事项是避免二次行为(Schlemiel 算法),这可以通过确保确定每个添加字符串的结尾来完成。如果是strncat(), 使用 size 参数要非常小心;它与strncpy()尺寸不同。而且您仍然可能需要使用strlen()标准函数,因为标准函数不会报告它们放置最后一个字符的字符串结尾 - 这比返回指向目标字符串第一个字符的指针更有帮助。

据我所知,没有标准功能可以做到这一点。

于 2011-08-25T19:45:44.110 回答
0

使用snprintf,这基本上总是关于组装字符串的任何问题的正确答案:

snprintf(buf, buflen, "%s%s%s", str1, str2, str3);

不幸的是,这不适用于“任意n”作为输入字符串计数;为此,只需编写您自己的 for 循环...

于 2011-08-25T20:12:02.777 回答