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

c中连接字符串的最有效方法,c,string,memory-management,C,String,Memory Management,考虑这个连接所有指定参数并在标准输出中打印它们的简单程序。我使用2个for循环来附加字符串,一个用于计算该字符串的长度,另一个用于连接字符串。有没有办法只用一个循环?重新分配要连接的每个字符串的内存不是更有效吗?Java的StringBuilder如何在C中实现?它会像我一样循环两次吗 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char** ar

考虑这个连接所有指定参数并在标准输出中打印它们的简单程序。我使用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);
}
#包括
#包括
#包括
int main(int argc,字符**argv)
{
尺寸长度=0;
//在i=1处启动for循环以跳过argv中指定的程序名
对于(int i=1;i
您的分配方法很有效,测量总长度并只分配一次。但是连接循环重复测量输出缓冲区从开始到连接到它的长度,导致二次运行时

要修复它,请边走边跟踪您的位置:

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;

您的分配方法是有效的,测量总长度并只分配一次。但是连接循环重复测量输出缓冲区从开始到连接到它的长度,导致二次运行时

要修复它,请边走边跟踪您的位置:

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;

最有效的方法可能是不使用任何
str
函数,而是“手动”复制字符:

char*toAppend=malloc(len+1);
尺寸j=0;
对于(大小i=1;i
最有效的方法可能是不使用任何
str
函数,而是“手动”复制字符:

char*toAppend=malloc(len+1);
尺寸j=0;
对于(大小i=1;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 *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';
完成后释放资源

free(dest);

重新分配要连接的每个字符串的内存不是更有效吗

通常,重复的重新分配是最好避免的,但对于较小的短字符串,它实际上没有什么区别。专注于我的答案是
O(n)
。在循环中重新定位往往是
O(n*n)

如果性能非常关键,请尝试各种方法并对预期系统进行配置。一台机器上的速度可能在另一台机器上有所不同。通常,最好先编写一个合理清晰的方法

在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 *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';
完成后释放资源

free(dest);

重新分配要连接的每个字符串的内存不是更有效吗

通常,重复的重新分配是最好避免的,但对于较小的短字符串,它实际上没有什么区别。专注于我的答案是
O(n)
。在循环中重新定位往往是
O(n*n)


如果性能非常关键,请尝试各种方法并对预期系统进行配置。一台机器上的速度可能在另一台机器上有所不同。通常,最好先编写一个合理清晰的方法。

代码的问题是strcat
,每次迭代都会遍历整个字符串以找到最后一个字符,请使用移动指针。附带提示:编写
(char*)malloc(len*sizeof(char)+1)的可读性更强的方法是
malloc(len+1)
@Winter:Yep,因为
void*
不需要强制转换。@ElliottFrisch:您可以在C中实现类似java AbstractStringBuilder的东西,但与正确的方法相比,这是非常低效的,首先要分配正确的总大小。这样做很大程度上违背了编写C的目的;你会遇到编写C的困难和java的缓慢性。根据你的使用模式,你可能想考虑大小的字符串,而不是NUL终止的字符串。代码的问题是“代码> STRCAT/CODEC>,每次迭代都要通过整个字符串来查找最后一个字符,使用移动指针代替。提示:编写
(char*)malloc(len*sizeof(char)+1)
的一种更可读的方法是
malloc(len+1)
@Winter:yes,因为
void*
不需要强制转换。@ElliottFrisch:您可以在C中实现类似java AbstractStringBuilder的东西,但与正确的方法相比,它的效率非常低,首先要分配正确的总大小。这样做很大程度上违背了编写C的目的;你会遇到编写C的困难和java的缓慢性。根据你的使用模式,你可能想考虑大小的字符串,而不是NUL终止的字符串。OP的方法不是最有效的,而且显然OP对学习级联是有兴趣的。部分问题提到Java中的
StringBuilder
。感谢您的回答和警告。然而,这个程序的目的是创建一个小型的、可验证的示例。我实际上想要做的是在内存中使用字符串。甚至比
printf(“%s”,toAppend)
更好的是
fputs(toAppend,stdout)
。(我认为GCC实际上会对
free(dest);