用crt在线性时间内连接C字符串

时间:2011-08-25 19:36:51

标签: c string crt concat strcat

假设我们想将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()一样高效。

是否有这样的功能我不见了?

3 个答案:

答案 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”作为输入字符串计数;为此,只需编写自己的循环...