代码之家  ›  专栏  ›  技术社区  ›  Winter

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

  •  0
  • Winter  · 技术社区  · 8 年前

    #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);
    }
    
    3 回复  |  直到 8 年前
        1
  •  2
  •   R.. GitHub STOP HELPING ICE    8 年前

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

    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]);
    
        2
  •  2
  •   chux    8 年前

    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);
    

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

    通常,重复的重新分配是最好的避免,但对于小的短字符串,它真的没有什么区别。专注于 big O . 我的答案是 O(n) O(n*n) .

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

        3
  •  0
  •   DYZ    8 年前

    最有效的方法可能是不使用任何 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