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

标签 c string memory-management

考虑这个连接所有指定参数并在标准输出中打印它们的简单程序。我使用了 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 - 在c中连接字符串的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52415807/

相关文章:

CMS_encrypt 使用 ECDH key

c - Microblaze 交叉编译器找不到 clock_gettime

c++ - 如何在C/C++中保存数据?

c# - 自定义列表<string[]> 排序

python - 如何在特定字符(实际上是一组字符)处拆分字符串,但具有指定的长度

r - R Windows 64 位版本中尚不支持长向量错误

c++ - 如何检查内存的释放

c - int 是 4 个字节,但仍然可以存储在 char 中,为什么没有溢出

javascript - 无法将字符从一个字符串替换为另一个字符串 - 这是 Javascript 错误吗?

c++ - 为什么会出现这种性能下降?