连接字符串时性能不佳的原因是内存的重新分配。Joel Spolsky 在他的文章Back to basics中讨论了这一点。他描述了连接字符串的简单方法:
Shlemiel 找到了一份街头画家的工作,在路中间画出虚线。第一天,他把一罐油漆带到路上,完成了 300 码的路。“那还不错!” 他的老板说,“你是一个快速的工人!” 并付给他一个戈比。
第二天,Shlemiel 只完成了 150 码。“嗯,那不如昨天好,但你仍然是一个快速的工人。150码是体面的,”并付给他一个戈比。
第二天,Shlemiel 粉刷了 30 码的道路。“只有三十个!” 他的老板喊道。“这不可接受!第一天你做了十倍的工作!这是怎么回事?”
“我无能为力,”Shlemiel 说。“我每天都离油漆罐越来越远!”
如果可以,您想知道目标缓冲区在分配之前需要多大。唯一现实的方法是调用strlen
所有要连接的字符串。然后分配适当数量的内存并使用稍微修改的版本strncpy
返回指向目标缓冲区末尾的指针。
// Copies src to dest and returns a pointer to the next available
// character in the dest buffer.
// Ensures that a null terminator is at the end of dest. If
// src is larger than size then size - 1 bytes are copied
char* StringCopyEnd( char* dest, char* src, size_t size )
{
size_t pos = 0;
if ( size == 0 ) return dest;
while ( pos < size - 1 && *src )
{
*dest = *src;
++dest;
++src;
++pos;
}
*dest = '\0';
return dest;
}
请注意如何将size
参数设置为目标缓冲区结束前剩余的字节数。
这是一个示例测试功能:
void testStringCopyEnd( char* str1, char* str2, size_t size )
{
// Create an oversized buffer and fill it with A's so that
// if a string is not null terminated it will be obvious.
char* dest = (char*) malloc( size + 10 );
memset( dest, 'A', size + 10 );
char* end = StringCopyEnd( dest, str1, size );
end = StringCopyEnd( end, str2, size - ( end - dest ) );
printf( "length: %d - '%s'\n", strlen( dest ), dest );
}
int main(int argc, _TCHAR* argv[])
{
// Test with a large enough buffer size to concatenate 'Hello World'.
// and then reduce the buffer size from there
for ( int i = 12; i > 0; --i )
{
testStringCopyEnd( "Hello", " World", i );
}
return 0;
}
产生:
length: 11 - 'Hello World'
length: 10 - 'Hello Worl'
length: 9 - 'Hello Wor'
length: 8 - 'Hello Wo'
length: 7 - 'Hello W'
length: 6 - 'Hello '
length: 5 - 'Hello'
length: 4 - 'Hell'
length: 3 - 'Hel'
length: 2 - 'He'
length: 1 - 'H'
length: 0 - ''