首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C中执行大量的字符串连接?

在C中执行大量的字符串连接?
EN

Stack Overflow用户
提问于 2013-01-11 07:07:05
回答 5查看 428关注 0票数 5

我正在将一些代码从Java移植到C,到目前为止一切都很顺利。

但是,我在Java中有一个特殊的函数,它可以自由使用StringBuilder,如下所示:

代码语言:javascript
复制
StringBuilder result = new StringBuilder();
// .. build string out of variable-length data
for (SolObject object : this) {
    result.append(object.toString());
}
// .. some parts are conditional
if (freezeCount < 0) result.append("]");
else result.append(")");

我知道SO不是一个代码翻译服务,但我并不是要求任何人来翻译上面的代码。

我想知道如何在C中有效地执行这种大容量字符串连接。它大多是小字符串,但每个字符串都由一个条件决定,所以我不能将它们组合到一个简单的sprintf调用中。

我如何才能可靠地进行这种类型的字符串连接?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-01-11 07:23:52

将大量“对象”转换为字符串的一种相当“聪明”的方法是:

代码语言:javascript
复制
 char buffer[100];
 char *str = buffer;
 str += sprintf(str, "%06d", 123);
 str += sprintf(str, "%s=%5.2f", "x", 1.234567);

这是相当有效的,因为sprintf返回复制的字符串的长度,所以我们可以通过返回值“向前移动”字符串,并不断填充。

当然,如果有真正的Java对象,那么您需要弄清楚如何将Java风格的ToString函数转换为C的printf家族中的"%somethign“。

票数 4
EN

Stack Overflow用户

发布于 2013-01-11 07:12:10

strcat()的性能问题在于,它必须扫描目标字符串以找到终止的\0',然后才能开始向其追加内容。

但请记住,strcat()不接受字符串作为参数,它接受指针。

如果维护一个单独的指针,该指针始终指向要追加的字符串的终止'\0',则可以将该指针用作strcat()的第一个参数,而不必每次都重新扫描它。在这个问题上,您可以使用strcpy() rater而不是strcat()

保持这个指针的值,并确保留出足够的空间作为练习。

注意:您可以使用strncat()来避免覆盖目标数组的结尾(尽管它会自动截断您的数据)。为此,我不推荐使用strncpy()。参见my rant on the subject

如果您的系统支持它们,那么(非标准的) strcpy()strlcat()函数对这类事情很有用。它们都返回它们试图创建的字符串的总长度。但是它们的使用降低了代码的可移植性;另一方面,您可以在任何地方使用开源实现。

另一种解决方案是对要追加的字符串调用strlen()。这并不理想,因为它会被扫描两次,一次由strcat()扫描,一次由strlen()扫描--但至少它避免了重新扫描整个目标字符串。

票数 2
EN

Stack Overflow用户

发布于 2013-01-11 07:43:05

连接字符串时性能不佳的原因是内存的重新分配。Joel Spolsky在他的文章Back to basics中讨论了这一点。他描述了连接字符串的简单方法:

Shlemiel找到了一份街道油漆工的工作,他在路中间画虚线。第一天,他带着一罐油漆上路,完成了300码的路程。“这真是太好了!”他的老板说:“你干得真快!”然后付给他一个科比。

第二天,施莱米尔只完成了150码。“嗯,这远没有昨天那么好,但你仍然是一个速度很快的工人。150码是值得尊敬的,”他付给他一个科比。

第二天,施莱米尔画了30码的路。“只有30个!”他的老板喊道。“这是不能接受的!第一天你就做了十倍的工作!这是怎么回事?”

“我忍不住,”施莱米尔说。“我一天比一天离油漆罐越来越远!”

如果可以,您希望在分配目标缓冲区之前知道它需要多大。要做到这一点,唯一实际的方法是对要连接的所有字符串调用strlen。然后分配适当数量的内存,并使用稍微修改过的strncpy版本,该版本返回一个指向目标缓冲区末尾的指针。

代码语言:javascript
复制
// 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参数设置为在目标缓冲区结束之前剩余的字节数。

下面是一个测试函数示例:

代码语言:javascript
复制
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;
}

这会产生:

代码语言:javascript
复制
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 - ''
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14268928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档