簡體   English   中英

連接c中字符串的最有效方法

[英]Most efficient way to concatenate strings in c

考慮一下這個簡單的程序,該程序將所有指定的參數連接起來並在標准輸出中打印它們。 我使用了2個for循環來附加字符串,其中一個用於計算字符串的長度,另一個用於連接字符串。 有沒有辦法只做一次循環? 為每個要連接的字符串重新分配內存不是更有效,是嗎? Java的StringBuilder如何用C實現? 它會像我一樣循環兩次嗎?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    size_t len = 0;

    // start for loop at i = 1 to skip the program name specified in argv
    for(int i = 1; i < argc; i++)
        len += strlen(argv[i]) + 1; // +1 for the space 

    char* toAppend = (char*)malloc(len * sizeof(char) + 1);
    toAppend[0] = '\0'; // first string is empty and null terminated 

    for(int i = 1; i < argc; i++)
    {
        strcat(toAppend, argv[i]);
        strcat(toAppend, " ");
    }

    printf(toAppend);
    free(toAppend);
}

您的分配方法非常有效,可以測量總長度並僅分配一次。 但是,串聯循環從開始到連接都反復測量輸出緩沖區的長度,從而導致二次運行時間。

要解決此問題,請跟蹤您的位置:

size_t pos = 0;
for(int i = 1; i < argc; i++) {
    size_t len = strlen(argv[i]);
    memcpy(toAppend+pos, argv[i], len);
    pos += len;
    toAppend[pos] = ' ';
    pos++;
}
toAppend[pos] = 0;

這是實際在內存中進行連接的最有效方法,但最有效的方法是不進行連接 代替:

for(int i = 1; i < argc; i++)
    printf("%s ", argv[i]);

stdio被緩沖的全部原因是,您不必構建任意長度的內存緩沖區即可進行有效的輸出。 而是自動緩沖到固定大小,並在緩沖區已滿時刷新。

請注意,如果輸入的任何地方都包含%字符,則使用printf是錯誤的,並且很危險; 它應該是printf("%s", toAppend);

如果您是在寫POSIX(或POSIX-ish)系統而不是普通的C語言,則另一個選擇是fmemopen ,它使您可以像這樣編寫循環:

for(int i = 1; i < argc; i++)
    fprintf(my_memfile, "%s ", argv[i]);

連接字符串在c中的有效方法

一種有效的方法是計算字符串長度-並記住它們。

size_t sum = 1; // for \0
if (argc > 2) sum += argc - 2.  // spaces
size_t length[argc];  // This is a VLA, available C99 and optionally in C11
for(int i = 1; i < argc; i++)
  length[i] = strlen(argv[i]);
  sum += length[i];
}

然后分配,然后檢查錯誤。

char *dest = malloc(sum);
if (dest == NULL) Handle_OutOfMemory();

依次復制每個字符串

char *p = dest;
for(int i = 1; i < argc; i++)
  // Use either memcpy() or strcpy().
  // memcpy() tends to be faster for long strings than strcpy().
  memcpy(p, argv[i], length[i]);  
  p += length[i]; // advance insertion point
  if (i > 1) {
    *p++ = ' '; // space separators
  }
}
*p = '\0';

現在使用dest[]

printf("<%s>\n", dest);

完成后釋放資源。

free(dest);

為每個要連接的字符串重新分配內存不是更有效,是嗎?

通常最好避免重復性的重新分配,但是對於較小的短字符串,確實沒有什么區別。 專注於大O。 我的答案是O(n) 在循環中重定位往往是O(n*n)

如果性能至關重要,請針對目標系統嘗試各種方法和配置文件。 關鍵在於在一台機器上最快的速度在另一台機器上可能有所不同。 通常最好先編寫一個合理的清晰方法。

最有效的方法可能是不使用任何str函數並“手動”復制字符:

char* toAppend = malloc(len + 1);

size_t j = 0;
for(size_t i = 1; i < argc; i++)
{
  for(size_t k = 0; argv[i][k]; k++)
    toAppend[j++] = argv[i][k];
  toAppend[j++] = ' ';
}
toAppend[j - 1] = '\0'; // Remove the last space and NULL-terminate the string

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM