How to properly glue two strings in C?

When executing the code

#include <stdio.h>
#include <string.h>

int main() {
    char *first = "first";
    char *second = "second";
    char *third = strcat(first, second);
}

A segmentation error occurs.

 10
c
Author: zed, 2010-10-15

8 answers

If the contents of the strings are known at the compilation stage, then the gluing can also be organized at the compilation stage

#define FIRST  "first"
#define SECOND "second"

int main(void) 
{
    const char *first  = FIRST;
    const char *second = SECOND;
    const char *third  = FIRST SECOND;
}

But it really depends on what you need.

For run-time gluing, using the strcat function is not a good idea, because each time the function is glued together, it scans the already constructed part of the string over and over again. (For this reason, strcat is actually a useless function.) It is better to use the usual one for this purpose. snprintf

#include <stdio.h>

int main(void) 
{
    const char *first  = "first";
    const char *second = "second";

    char third[512];
    snprintf(third, sizeof third, "%s%s", first, second);
}

And which method of reserving memory for the destination string is more suitable for you depends on your specific circumstances and requirements.

 9
Author: AnT, 2018-06-28 15:26:25

To glue 2 lines in C, follow these steps:

  1. Use the malloc function to allocate a block of memory (result) sufficient to store both lines in it (and do not forget about the space for the trailing zero)

  2. Use the memcpy function to copy the first line s1 to the beginning of the selected block

  3. Using the same function memcpy, copy the second line s2, along with its zero, to the selected block, with an offset of first row size

  4. After you have made some manipulations with the received string, you need to release it, using the function free

Example:

    char* concat(char *s1, char *s2) {

        size_t len1 = strlen(s1);
        size_t len2 = strlen(s2);                      

        char *result = malloc(len1 + len2 + 1);

        if (!result) {
            fprintf(stderr, "malloc() failed: insufficient memory!\n");
            return NULL;
        }

        memcpy(result, s1, len1);
        memcpy(result + len1, s2, len2 + 1);    

        return result;
    }

How to use it:

    char *s = concat("first", "second");
    printf("%s\n", s);
    free(s);
 5
Author: zed, 2016-04-22 19:27:23

For strcat, the first argument must point to a buffer of sufficient length to fit the resulting (glued) string. The variables first and second are pointers to string literals, i.e. data on such pointers cannot be changed. This results in undefined behavior (UB).

The original example can be rewritten as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    const char* first = "first"; // const явно указывает, что такие данные менять нельзя
    const char* second = "second";
    char* buff = calloc(strlen(first) + strlen(second) + 1, 1);
    strcat(buff, first);
    strcat(buff, second);
    printf("%s\n", buff);
    free(buff);
}

Execution result

 3
Author: αλεχολυτ, 2016-04-22 20:27:12

The simplest option is to explicitly reserve the memory with a margin for the first line (to which the second line will be "glued").:

#include <stdio.h>
#include <string.h>

int main() {
    char first[256] = "first";
    char second[] = "second";
    strcat(first, second);
    puts(first);
    return 0;
}

Execution result: http://ideone.com/OOXUCV

 2
Author: insolor, 2016-04-22 22:16:31
#include <stdlib.h>
#include <string.h>

char* concat(char *s1, char *s2)
{
    char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 нужен для нуль-терминатора строки.
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}
  1. Allocating the required amount of memory
  2. We glue and return the pointer to the beginning of the memory block.
 1
Author: Daniels Šatcs, 2016-04-22 23:28:17

Since there is such a massive response to the necropost, I will make my contribution.

GNU has a very convenient analog sprintf -- asprintf, which places the result of the "output" of its arguments in dynamic memory (uses malloc).

Accordingly, the program can be as follows:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int 
main (int ac, char *av[])
{
  char first[] = "first", 
    second[] = "second";
  char *third;

  if (asprintf(&third, "%s%s", first, second) < 0)
    third = strdup(strerror(errno));

  return puts(third) == EOF;
}

And if you do not have it (asprintf), then it is easy to write

static int 
asprintf (char **ps, const char *fmt, ...)
{
  //   puts("my asprintf");
  va_list ap;
  va_start(ap, fmt);
  int rc = vsnprintf(*ps, 0, fmt, ap);
  va_end(ap);
  if (rc >= 0) {
    if ((*ps = (char *)malloc(rc + 2))) {
      va_start(ap, fmt);
      rc = vsnprintf(*ps, rc + 1, fmt, ap);
      va_end(ap);
    } else
      rc = -1;
  }

  return rc;
}

(or copy-paste) and use it without any #define _GNU_SOURCE even in windows (at least MinGW successfully broadcasts).

 1
Author: avp, 2016-04-22 23:50:07

Because the strcat() function adds

  • the string pointed to by the second parameter ("second")
  • To the string pointed to by the first parameter ("first")

  • And then rotates the first parameter-pointer to the first row, but to which the second row is now added,

You need to allocate enough memory for the first parameter for the connected string ("firstsecond") - or in compile-time, or dynamically.

 1
Author: MarianD, 2018-06-28 15:18:28

The problem is that the strcat function does not allocate memory, but copies from one string to another. Since the length of the first line is less than the length of the second, the memory is flushed. You need to change the code, for example, like this.

#include <stdio.h>
#include <string.h>

int main() {
    char first[7] = "first";
    char second[7] = "second";
    char *third = strcat(first, second);
}
 -1
Author: stanislav, 2010-10-15 17:39:15