2011-05-18 92 views
0

我正在寻找一种有效的方法来追加多个字符串。
它应该工作的方式是C++ std :: string :: append或JAVA StringBuffer.append。C字符串追加

我写了一个函数,它实际上重新分配以前的源指针并执行strcat。

我相信这不是一个有效的方法,因为编译器可以实现这个自由和malloc。

我能想到的其他方式(如std :: vector)是分配内存(例如1KB)并执行strcpy。在这种情况下,每个追加调用将检查总需求分配是否大于(1200字节)批量分配的数量,重新分配至2KB。但在这种情况下,会浪费一些内存。

我正在寻找上述之间的平衡,但首选是性能。

其他方法是可能的。请建议。

+1

['strcat'](http://www.cplusplus.com/reference/clibrary/cstring/strcat的/)? – Santa 2011-05-18 16:58:08

+1

strcat没有任何帮助,它不会为您分配任何空间,也不会为您检查边界,而且效率非常低,除非您记得前一个字符串的结尾。 – nos 2011-05-18 17:01:42

+1

级联通常只是C中错误的成语*。除非没有其他选项,否则不要使用它。 (这在其他语言中也是效率低下的,但其他语言完全缺乏有效的替代方法,所以它是可以接受的。)顺便说一下,如果您想使用C++或Java语言,请使用其中一种语言,而不要使用C语言。试图在计算机语言就像试图在人类语言之间翻译它们一样荒谬。 – 2011-05-18 17:06:52

回答

4

我会将每个字符串添加到列表中,并将每个新字符串的长度添加到运行总数。然后,当你完成时,为该总数分配空间,遍历列表并将每个字符串strcpy分配给新分配的空间。

2

经典方法是每次缓冲区太小时加倍缓冲区。

从一个“合理的”缓冲区开始,所以你不需要做大小为1,2,4,8,16的realloc() s,这将会被大量的字符串击中。

从1024字节开始,意味着如果您点击2048,则会有一个realloc(),如果您点击4096,则会有一秒钟,等等。如果猖獗的内存消耗会让你感到恐慌,那么一旦达到65536字节或其他任何适当的大小,就限制其增长速度,这取决于你的数据和内存容量。

此外请确保您缓冲当前长度,因此您可以执行strcpy()而不必先行走字符串以查找长度。

+0

您应该提到,其原因是为了避免在重复级联上出现'O(n^2)'最坏情况复制性能。 – 2011-05-18 17:06:01

+0

@unwind:我们仍然需要strlen来查找字符串长度,以检查要添加的新字符串是否溢出...不是吗? – Mayank 2011-05-18 17:21:51

+0

@Mayank - 现在你回到了C字符串的低效率。 Java和C++通过记住每个字符串的长度和每个缓冲区的大小来做到这一点。他们不必一直计数字符!更高级别的操作**可以**更高效。 – 2011-05-18 17:34:37

0

样的功能来连接字符串

void 
addToBuffer(char **content, char *buf) { 
    int textlen, oldtextlen; 
    textlen = strlen(buf); 
    if (*content == NULL) 
     oldtextlen = 0; 
    else 
     oldtextlen = strlen(*content); 
    *content = (char *) realloc((void *) *content, (sizeof(char)) * (oldtextlen+textlen+1)); 
    if (oldtextlen != 0) { 
     strncpy(*content + oldtextlen, buf, textlen + 1); 
    } else { 
     strncpy(*content, buf, textlen + 1); 
    } 
} 

int main(void) { 
    char *content = NULL; 
    addToBuffer(&content, "test"); 
    addToBuffer(&content, "test1"); 
} 
0

我会做这样的事情:

typedef struct Stringbuffer { 
    int capacity;  /* Maximum capacity. */ 
    int length;  /* Current length (excluding null terminator). */ 
    char* characters; /* Pointer to characters. */ 
} Stringbuffer; 

BOOL StringBuffer_init(Stringbuffer* buffer) { 
    buffer->capacity = 0; 
    buffer->length = 0; 
    buffer->characters = NULL; 
} 

void StringBuffer_del(Stringbuffer* buffer) { 
    if (!buffer) 
     return; 

    free(buffer->characters); 

    buffer->capacity = 0; 
    buffer->length = 0; 
    buffer->characters = NULL; 
} 

BOOL StringBuffer_add(Stringbuffer* buffer, char* string) { 
    int len; 
    int new_length; 

    if (!buffer) 
     return FALSE; 

    len = string ? strlen(string) : 0; 

    if (len == 0) 
     return TRUE; 

    new_length = buffer->length + len; 

    if (new_length >= new_capacity) { 
     int new_capacity; 

     new_capacity = buffer->capacity; 

     if (new_capacity == 0) 
      new_capacity = 16; 

     while (new_length >= new_capacity) 
      new_capacity *= 2; 

     new_characters = (char*)realloc(buffer->characters, new_capacity); 
     if (!new_characters) 
      return FALSE; 

     buffer->capacity = new_capacity; 
     buffer->characters = new_characters; 
    } 

    memmove(buffer->characters + buffer->length, string, len); 
    buffer->length = new_length; 
    buffer->characters[buffer->length] = '\0'; 

    return TRUE; 
}