連接字符串時性能較差的原因是內存重新分配。 Joel Spolsky在他的文章Back to basics中對此進行了討論。他描述了連接字符串的簡單方法:
Shlemiel找到了一個街頭畫家的工作,在路中間畫了虛線。第一天,他將一罐油漆塗在路上,完成了300碼的道路。 「這很好!」他的老闆說,「你是一個快速的工人!」並支付給他一個科比。
第二天什萊米爾只能完成150碼。 「那麼,這還不如昨天,但你仍然是一個快速的工人,150碼是可敬的,並支付他科比。
第二天什萊米爾油漆30碼的道路。 「只有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 - ''
你嚴格地用C?或者你也可以使用C++嗎? – Nico
那麼你可以將它們合併成一堆sprintf()調用。只需使用返回值... – wildplasser
@Nico我使用純C,並且我想避免C++。 –