【问题标题】:What is a safe way to join strings in C?在 C 中加入字符串的安全方法是什么?
【发布时间】:2011-03-10 15:48:59
【问题描述】:

我需要从两个字符串构造一个文件的路径。我可以使用这个(虽然没有测试):

/* DON'T USE THIS CODE! */
/* cmp means component */
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
unsigned len = strlen(path_cmp1);
char *path = path_cmp1;
for (int i = 0; i < strlen(path_cmp2); i++) {
  path[len + i] = path_cmp2[i];
}

但是我猜这可能会导致内存损坏。有没有更好的方法来做到这一点,或者标准库中是否有这个功能?

【问题讨论】:

    标签: c arrays string join


    【解决方案1】:
    #include <stdlib.h>
    #include <string.h>
    
    char *join(const char* s1, const char* s2)
    {
        char* result = malloc(strlen(s1) + strlen(s2) + 1);
    
        if (result) // thanks @pmg
        {
            strcpy(result, s1);
            strcat(result, s2);
        }
    
        return result;
    }
    

    这很简单,可以就地编写,尤其是当您有多个字符串要连接时。

    请注意,这些函数返回其目标参数,因此您可以编写

    char* result = malloc(strlen(s1) + strlen(s2) + 1);
    assert(result);
    strcat(strcpy(result, s1), s2);
    

    但这不太可读。

    【讨论】:

    • +1 ... 但if (result) { strcpy; strcat; } 如果 malloc 失败则自动返回 NULL
    • “就地编写”是指join(join("foo", "bar"), "baz")吗?这将导致严重的内存泄漏。您的第二个示例不仅丑陋,而且由于缺乏错误检查而不安全。
    • @pmg 我在使用 malloc 时总是检查NULL
    • @larsman:不,我的意思是完全编写 malloc、strcpy 和 strcat 而不是 join 函数。
    • 此代码扫描 s1 3 次和 s2 两次以找出它们的长度。如果您想要更快,您只需扫描它们中的每一个。
    【解决方案2】:
    #include <stdio.h> 
    
    char *a = "hello ";
    char *b = "goodbye";
    char *joined;
    
    asprintf(&joined, "%s%s", a, b)
    

    【讨论】:

    • 非标准,但在snprintf 方面实施起来并不难。 +1。
    【解决方案3】:

    这段代码有几个问题: 1 - 在for循环上调用strlen是个坏主意,它会计算每次迭代的字符串长度,所以最好在循环之前调用一次并将结果保存在一个变量中。

    2 - 同样的 strlen 问题适用于循环内的 strlen(path_cmp1),在循环之前调用它并增加它的大小。

    最后,最好简单地复制两个字符串并将它们存储在动态分配的字符串中,例如:

    char *join_strings(const char* s1, const char* s2)
    {
        size_t lens1 = strlen(s1);
        size_t lens2 = strlen(s2);
    
        //plus 1 for \0
        char *result = malloc(lens1 + lens2 + 1);
    
        if(result)
        {
            memcpy(result, s1, lens1);
            memcpy(result+lens1, s2, lens2+1);
        }
    
        //do not forget to call free when do not need it anymore
        return result;
    }
    

    【讨论】:

    • 是的,编写“清晰”代码会降低性能:)
    • 推荐if(result) { }左右两个memcpy()
    【解决方案4】:

    strcatstrncat

    【讨论】:

      【解决方案5】:
      char *path_cmp1 = "/Users/john/";
      char *path_cmp2 = "foo/bar.txt";
      
      int firstLength = strlen(path_cmp1);
      int secondLength = strlen(path_cmp2);
      char *both = malloc(firstLength+secondLength+1);
      memcpy(both, path_cmp1, firstLength);
      memcpy(both+firstLength, path_cmp2, secondLength+1);
             // this +1 copyes the second string's null-terminator too.
      

      【讨论】:

        【解决方案6】:

        用两个输入的长度和 strcpy/strcat 输入的长度创建一个新字符串,不要忘记空终止符。

        【讨论】:

          【解决方案7】:

          使用strcat。 (你说得对,你的代码会导致内存损坏。)

          【讨论】:

            【解决方案8】:

            string.h 中的strcat 怎么样?

            【讨论】:

              【解决方案9】:

              path 只是一个指向path_cmp1 的指针,您正在尝试访问数组末尾之外的内容。偶尔这会起作用,但在绝大多数情况下,您会导致内存损坏。

              正如其他人指出的那样,使用 strcat 连接字符串。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-08-13
                • 2021-12-25
                • 2012-02-08
                • 1970-01-01
                • 2016-07-26
                • 1970-01-01
                相关资源
                最近更新 更多