2011-05-18 143 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; 
}