在C中连接string,哪种方法更有效率?

我碰到这两个方法来连接string:

共同部分:

char* first= "First"; char* second = "Second"; char* both = malloc(strlen(first) + strlen(second) + 2); 

方法1:

 strcpy(both, first); strcat(both, " "); strcat(both, second); 

方法2:

 sprintf("%s %s", first, second); 

在这两种情况下,两者的内容将是"First Second"

我想知道哪一个更高效(我必须执行几个级联操作),或者如果你知道更好的方法来做到这一点。

谢谢你的时间。

编辑:在第一种情况下,空间可能已经在一个string内。

为了可读性,我会一起去的

 char * s = malloc(snprintf(NULL, 0, "%s %s", first, second) + 1); sprintf(s, "%s %s", first, second); 

如果你的平台支持GNU扩展,你也可以使用asprintf()

 char * s = NULL; asprintf(&s, "%s %s", first, second); 

如果您遇到MS C Runtime,则必须使用_scprintf()来确定结果string的长度:

 char * s = malloc(_scprintf("%s %s", first, second) + 1); sprintf(s, "%s %s", first, second); 

以下将最有可能是最快的解决scheme:

 size_t len1 = strlen(first); size_t len2 = strlen(second); char * s = malloc(len1 + len2 + 2); memcpy(s, first, len1); s[len1] = ' '; memcpy(s + len1 + 1, second, len2 + 1); // includes terminating null 

不要担心效率:使您的代码可读性和可维护性。 我怀疑这些方法之间的区别在你的程序中很重要。

这是你的一些疯狂,我真的去测量它。 血淋淋的地狱,想象一下。 我想我得到了一些有意义的结果。

我使用双核P4,运行Windows,使用mingw gcc 4.4,用“gcc foo.c -o foo.exe -std = c99 -Wall -O2”构build。

我从原始post中testing了方法1和方法2。 最初将malloc保持在基准循环之外。 方法1比方法2快了48倍。奇怪的是,从构build命令中删除-O2使得得到的exe快了30%(还没有调查为什么)。

然后我添加了一个malloc,并在循环内部释放。 这使方法1减慢了4.4倍。 方法2减慢了1.1倍。

所以,malloc + strlen + free不会占据主导地位,足以避免sprintf的价值。

这是我使用的代码(除了循环是用<而不是!=实现的,但打破了这篇文章的HTML渲染):

 void a(char *first, char *second, char *both) { for (int i = 0; i != 1000000 * 48; i++) { strcpy(both, first); strcat(both, " "); strcat(both, second); } } void b(char *first, char *second, char *both) { for (int i = 0; i != 1000000 * 1; i++) sprintf(both, "%s %s", first, second); } int main(void) { char* first= "First"; char* second = "Second"; char* both = (char*) malloc((strlen(first) + strlen(second) + 2) * sizeof(char)); // Takes 3.7 sec with optimisations, 2.7 sec WITHOUT optimisations! a(first, second, both); // Takes 3.7 sec with or without optimisations //b(first, second, both); return 0; } 
 size_t lf = strlen(first); size_t ls = strlen(second); char *both = (char*) malloc((lf + ls + 2) * sizeof(char)); strcpy(both, first); both[lf] = ' '; strcpy(&both[lf+1], second); 

他们应该几乎相同。 差异是不重要的。 我会用sprintf去,因为它需要更less的代码。

差别不大可能很重要:

  • 如果你的string很小, malloc会淹没string连接。
  • 如果你的string很大,复制数据的时间将淹没strcat / sprintf之间的差异。

正如其他海报所说,这是一个不成熟的优化。 专注于algorithmdevise,如果分析表明它是一个性能问题,则只能回到这个问题。

这就是说…我怀疑方法1会更快。 有一些—不可否认的是开销来分析sprintf格式string。 而strcat更可能是“内联”的。

sprintf()被devise为处理远远超过string,strcat()是专家。 但我怀疑你正在出汗的小东西。 Cstring从根本上来说效率低下,使得这两种方法之间的差异微不足道。 请阅读Joel Spolsky的“Back to Basics”以了解更多细节。

这是C ++通常比C执行更好的一个例子。对于使用std :: string的重量级string处理来说,可能会更高效,更安全。

[编辑]

[第二编辑]更正的代码(在Cstring实现中迭代太多),时间和结论相应地改变

我对Andrew Bainbridge的评论感到惊讶,std :: string比较慢,但是他没有发布这个testing用例的完整代码。 我修改了他(自动化时间)并添加了一个std :: stringtesting。 该testing是在VC ++ 2008(本机代码),默认的“发布”选项(即优化),速龙双核,2.6GHz。 结果:

 C string handling = 0.023000 seconds sprintf = 0.313000 seconds std::string = 0.500000 seconds 

因此尽pipeCstring约定固有的效率低下,但strcat()的速度更快(你的milage可能会因编译器和选项而异),并支持我最初的build议,即sprintf()带有很多不需要的行李。 它仍然是迄今为止最不可读和安全的,所以当性能不重要时,IMO几乎没有任何优点。

我也testing了一个std :: stringstream的实现,这又慢了很多,但是对于复杂的string格式化仍然有优点。

更正后的代码如下:

 #include <ctime> #include <cstdio> #include <cstring> #include <string> void a(char *first, char *second, char *both) { for (int i = 0; i != 1000000; i++) { strcpy(both, first); strcat(both, " "); strcat(both, second); } } void b(char *first, char *second, char *both) { for (int i = 0; i != 1000000; i++) sprintf(both, "%s %s", first, second); } void c(char *first, char *second, char *both) { std::string first_s(first) ; std::string second_s(second) ; std::string both_s(second) ; for (int i = 0; i != 1000000; i++) both_s = first_s + " " + second_s ; } int main(void) { char* first= "First"; char* second = "Second"; char* both = (char*) malloc((strlen(first) + strlen(second) + 2) * sizeof(char)); clock_t start ; start = clock() ; a(first, second, both); printf( "C string handling = %f seconds\n", (float)(clock() - start)/CLOCKS_PER_SEC) ; start = clock() ; b(first, second, both); printf( "sprintf = %f seconds\n", (float)(clock() - start)/CLOCKS_PER_SEC) ; start = clock() ; c(first, second, both); printf( "std::string = %f seconds\n", (float)(clock() - start)/CLOCKS_PER_SEC) ; return 0; } 

既不是非常有效的,因为两种方法都必须计算string长度或每次扫描。 相反,既然你计算了单个string的strlen(),把它们放在variables中,然后只是strncpy()两次。

我不知道情况二是有任何真正的连接。 背靠背打印不构成串联。

告诉我,这将会更快:

1)a)将stringA复制到新缓冲区b)将stringB复制到缓冲区c)将缓冲区复制到输出缓冲区

要么

1)将stringA复制到输出缓冲区b)将stringb复制到输出缓冲区

  • 与sprintf相比,strcpy和strcat更简单,它需要parsing格式string
  • strcpy和strcat都很小,所以它们通常会被编译器内联,从而节省更多额外的函数调用开销。 例如,在llvm中,strcat将使用strlen内联来查找复制开始位置,然后是一个简单的存储指令