【问题标题】:concatenate strings with memmove() in function在函数中使用 memmove() 连接字符串
【发布时间】:2015-01-12 15:06:33
【问题描述】:

我想使用返回结果字符串的函数连接两个字符串。它会是这样的:

char *String_Concat (char *String_1, char *String_2)
{
    char *StringResult;

    //memmove String_1 to StringResult
    //memmove String_2 to StringResult

    return StringResult;
}

我想知道这是否是一种好方法,因为我对内存管理知之甚少。 StringResult 没有定义的长度,我不确定两次 memmove 操作后会发生什么。

我想StringResult会被函数本身清理掉,因为我不使用malloc(),对吗?

【问题讨论】:

  • 但是你必须使用malloc!您还可以将字符串复制到哪里?
  • memmove 不是为了那个,它是为了重叠的内存块,你应该使用memcpy
  • 但是 memcpy() 不能很好地处理重叠。有那个空字符。
  • @CaTx 与重叠无关。
  • 您需要有一个足够大的缓冲区来保存结果,使用 malloc 或传入一个足够大的缓冲区是您的最佳选择。以 strcat 函数为例。您可以将第一个字符串 strcpy 到一个足够大的缓冲区中,然后将第二个字符串 strcat 到它。

标签: c string string-concatenation memmove


【解决方案1】:
char *String_Concat (char *String_1, char *String_2)
{
    size_t len1 = strlen(String_1);
    size_t len2 = strlen(String_2);
    char *StringResult = malloc(len1+len2+1);
    //might want to check for malloc-error...
    memcpy(StringResult, String_1, len1);
    memcpy(&StringResult[len1], String_2, len2+1);
    return StringResult;
}

所以,C 对对象有storage 的概念。对象的存储决定了它的生命周期,因为 C 不是垃圾回收的。如果要创建新字符串,则必须为其保留存储空间。最简单的方法是自动存储,但这与声明它的函数的作用域相关联,因此自动变量在函数返回后不再存在。或者,您可以使用 静态 存储,但它不能是可变大小的,并且对该函数的多次调用将使用相同的存储。最后,您可以使用已分配存储,这需要malloc()/calloc()/realloc()/free()

参见 C11 草案标准,6.2.4 Storage durations of objects 部分

【讨论】:

  • 我试过这样做。问题是 malloc() 需要一个 free() 。但是 free() 击败了'return StringResult'。看到我的问题了吗?
  • @CaTx free 不会打败任何你应该在返回后释放它的东西。
  • 使用返回字符串的函数负责在完成后释放它。一个不那么令人困惑的解决方案是在 sting_concat 函数之外对其进行 malloc,并将 malloc 的指针作为参数传递 - 这样您就没有隐藏在函数中的 malloc 并且更容易确保您的 malloc 和 frees 是配对。
  • @alk 顺便说一句,我与这个 OP 进行了交谈,他不想手动 free,显然他想几乎从字面上翻译他的 C# 代码。他想有一些单线。我赞成这个答案,这是我的第一个答案,虽然 EOF 在我之前发布了几秒钟,但这不是 OP 想要的。
  • @iharob:“他不想手动释放”那么 OP 最好使用 C# ...
【解决方案2】:

这是我将如何处理它,使用现有的字符串命令而不是 memcpy。我假设您想要类似 strcat 的东西,它不会影响源字符串。

char* string_concat(char *dest, const char* string1, const char* string2)
{
   strcpy(dest, string1);
   strcat(dest, string2);
   return dest;
}

要使用它,您需要传入一个指向您想要存储结果的缓冲区的指针。您可以使用 malloc 将其设置为您需要的大小。完成后释放它。

char *str1 = "abc";
char *str2 = "def";
size_t len = strlen(str1) + strlen(str2);
char *newstr = malloc(len + 1);
string_concat(newstr, str1, str2);
printf("%s\n", newstr);
free(newstr);

在不分配内存的情况下根本无法处理任意长度的字符串,因此除非您使用具有固定长度的字符数组,否则您将无法使用 malloc/free。如果您想抽象决定分配多大缓冲区的逻辑,您可以执行以下操作:

size_t string_concat(char* dest, char* string1, char* string2)
{
   if(!dest)
   {
      return strlen(string1) + strlen(string2) + 1;
   }
   strcpy(dest, string1);
   strcat(dest, string2);
   return 0;
}

那你可以这样问它分配多少:

char* newstr = malloc(string_concat(0, str1, str2));

但是你失去了它返回一个指向 dest 的指针的语法便利。

【讨论】:

  • 1+ 用于提出“试运行”选项! :-)
【解决方案3】:

这是一个非常糟糕的主意,并且该函数不会神奇地发生“清理”。

你不能这样做,这不是在 C 中实现字符串连接的有效方法。

必须在做任何事情之前确保有足够的可写内存,所以通常你必须调用malloc()

【讨论】:

    【解决方案4】:

    如果你想避免动态分配,你可以这样做

    int main( int argc, char **argv)
    {
        char        String_1[8] = "Exa";
        /*                   ^ enough space for Example\0 */
        const char *String_2    = "mple";
    
        printf("%s\n", strcat(String_1, String_2));
    
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      您必须使用malloc() 为生成的连接字符串动态分配一些内存。
      在这种情况下,调用者负责调用free() 来释放返回的字符串指针指向的内存。

      另一种方法是设计一个函数,该函数期望指向调用者分配的目标缓冲区的指针,该缓冲区大到足以存储总的结果字符串。

      按照第一个选项,您可以考虑这样的代码 (live on Ideone):

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      // Concatenates string1 and string2.
      // Returns the concatenated (string1+string2), or NULL on errors.
      // NOTE: Memory for the returned string is allocated with malloc() 
      // by the function, so the caller is responsible to release it with
      // a call to free().
      char *StringConcat(const char *string1, const char *string2)
      {
          char *stringResult;
          size_t len1;
          size_t len2;
      
          // Check for NULL pointers...
          // (Return NULL, or whatever your design is...)
          if (string1 == NULL || string2 == NULL) {
              return NULL;
          }
      
          len1 = strlen(string1);
          len2 = strlen(string2);
      
          // +1 for terminating NUL ('\0')
          stringResult = malloc(len1 + len2 + 1);
          if (stringResult == NULL) {
              return NULL; // Allocation error
          }
      
          // Copy characters from first string    
          // (exclduing the terminating NUL --> len1)
          memcpy(stringResult, string1, len1);
      
          // Copy characters from second string
          // (including the terminating NUL --> len2+1)
          memcpy(stringResult + len1, string2, len2+1);
      
          // Return destination string pointer to the caller.
          // NOTE: Memory must be freed by the caller calling free().
          return stringResult;
      }
      
      
      // *** TEST ***
      int main(void)
      {
          // Test the function
          char * str = StringConcat("Hello ", "World");
      
          // Print the resulting string
          printf("%s\n", str);
      
          // Don't forget to free() memory allocatd by the concat function
          free(str);
      
          // All right
          return 0;
      }
      

      【讨论】:

        【解决方案6】:

        为了完整起见,假设使用 memmove() 只是一个想法,而不是要求,strcpy()strcat() 是这里选择的函数,因为它们专门用于处理 C-“字符串”,即 @ 987654324@-终止char-arrays。

        #include  <stdlib.h> /* for malloc() */
        #include  <string.h> /* for strcpy() and strcat() */
        #include  <errno.h> /* for errno and EINVAL */
        
        char * stralloc_and_cat(const char * s1, const char * s2)
        { 
          char * s = NULL;
        
          if ((NULL == s1) || (NULL == s2))
          {
            errno = EINVAL;
          }
          else 
          {
            if (NULL != (s = malloc(strlen(s1) + strlen(s2) + 1)))
            {
              strcpy(s, s1);
              strcat(s, s2);
            }
          }
        
          return s;
        } 
        

        然后这样称呼它:

        #include  <stdlib.h>
        #include  <stdio.h>
        
        char * stralloc_and_cat(const char * s1, const char * s2);
        
        int main(void)
        {
          char * s1 = "hello ";
          char * s2 = "world";
        
          char s = stralloc_and_cat(s1, s2);
          if (NULL == s)
          {
            perror("stralloc_and_cat() failed");
          }
          else
          {
            printf("%s\n", s);
        
            free(s);
          }
        
          return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2018-01-16
          • 1970-01-01
          • 2021-02-15
          • 1970-01-01
          • 1970-01-01
          • 2014-05-26
          • 2018-05-28
          • 1970-01-01
          • 2016-07-03
          相关资源
          最近更新 更多