1

I want to concatenate two strings using a function that returns the resulting string. it would be something like this:

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

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

    return StringResult;
}

I wonder if that is a good way of doing that, since I know little about memory management. StringResult does not have a defined length, and I am not sure what will happen after two memmove operations.

I suppose StringResult will be cleaned up by the function itself, since I do not use malloc(), correct?

CaTx
  • 1,421
  • 4
  • 21
  • 42
  • But you *must* use `malloc`! Where else can you copy the strings to? – Jongware Jan 12 '15 at 15:08
  • `memmove` is not for that, it's for overlapping memory blocks, for that you should use `memcpy`. – Iharob Al Asimi Jan 12 '15 at 15:08
  • but memcpy() does not handle overlapping well. there is that null character. – CaTx Jan 12 '15 at 15:11
  • @CaTx that has nothing to do with overlapping. – Iharob Al Asimi Jan 12 '15 at 15:12
  • 1
    You'll need to have a buffer large enough to hold the result, either using malloc or passing in one that is large enough are your best options. Take a look at the strcat function for an example. You could strcpy the first string into a big enough buffer and then strcat the second string to it. – Katie Jan 12 '15 at 15:13

6 Answers6

4
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;
}

So, C has the concept of storage for objects. The storage of an object determines its lifetime, as C is not garbage-collected. If you want to create a new string, You must reserve storage for it. The easiest way would be automatic storage, but that is associated with the scope of the function it is declared in, so automatic variables cease to exist after function return. Alternatively, you could use static storage, but that cannot be of variable size, and multiple calls to the function would use the same storage. Finally, you can use allocated storage, which requires malloc()/calloc()/realloc()/free().

See C11 draft standard, section 6.2.4 Storage durations of objects

EOF
  • 6,273
  • 2
  • 26
  • 50
  • I tried doing that. the problem is malloc() required a free() with it. but free() defeats 'return StringResult'. see my problem? – CaTx Jan 12 '15 at 15:13
  • @CaTx `free` doesn't defeat anything you should free it after returning. – Iharob Al Asimi Jan 12 '15 at 15:14
  • The function that uses the returned string is responsible for freeing it when it is done with it. A less confusing solution is to malloc it outside of the sting_concat function, and pass in the malloc'ed pointer as a parameter - then you don't have a malloc hiding in the function and it is easier to make sure your mallocs and frees are paired up. – Katie Jan 12 '15 at 15:16
  • @alk by the way i had a conversation with this OP, he doesn't want to have to `free` manually, apparently he wants to translate his code from C# almost literally. He wants to have some oneliners. I upvoted this answer and it was my first answer, although EOF posted it before me by a few seconds, but it's not what the OP wants. – Iharob Al Asimi Jan 12 '15 at 15:29
  • @iharob: "*he doesn't want to have to free manually*" then the OP better stays with C# ... – alk Jan 12 '15 at 15:47
  • @alk I told the OP to use c++ instead, but the OP wants c. – Iharob Al Asimi Jan 12 '15 at 15:53
  • @iharob: Then point the OP to C tutorials and documentation. The standard is pretty useful... – EOF Jan 12 '15 at 15:55
  • thx everyone for the help. a 2-liner seems to be the best compromise now. – CaTx Jan 12 '15 at 16:08
2

Here's how I would handle it, using existing string commands instead of memcpy. I'm assuming you want something like strcat that doesn't affect the source strings.

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

To use it, you need to pass in a pointer to the buffer you want the result stored in. You can use malloc to make it the size you need. Free it when you're done.

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

There is simply no way to deal with arbitrary-length strings without allocating memory, so you'll be stuck with malloc/free unless you're using character arrays with fixed lengths. If you want to abstract the logic of deciding how big of a buffer to allocate you can do something like this:

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

Then you can ask it how much to allocate like this:

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

But you lose the syntactical convenience of it returning a pointer to dest.

Katie
  • 1,260
  • 10
  • 20
0

It's a very bad idea, and no "cleaning" will magically happen by the function.

You cannot do this, it's not a valid way to implement string concatenation in C.

You must make sure there's enough writable memory before doing anything, so in general you must call malloc().

unwind
  • 391,730
  • 64
  • 469
  • 606
0

If you want to avoid dynamic allocation you can do something like

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;
}
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

For completeness, assuming using memmove() was just an idea, not a requirement, strcpy() and strcat() are functions of choice here, as they are specially crafted to work on C-"strings", that is 0-terminated 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;
} 

And call it like this:

#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;
}
alk
  • 69,737
  • 10
  • 105
  • 255
0

You have to use malloc() to dynamically allocate some memory for the resulting concat string.
And in this case the caller is responsible to invoke free() to release the memory pointed by the returned string pointer.

An alternative would be to design a function expecting a pointer to a caller-allocated destination buffer, large enough to store the total resulting string.

Following the first option, you can consider code like this (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;
}
Mr.C64
  • 41,637
  • 14
  • 86
  • 162