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.
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.
To glue 2 lines in C, follow these steps:
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)Use the
memcpy
function to copy the first lines1
to the beginning of the selected blockUsing the same function
memcpy
, copy the second lines2
, along with its zero, to the selected block, with an offset of first row sizeAfter 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);
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);
}
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
#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;
}
- Allocating the required amount of memory
- We glue and return the pointer to the beginning of the memory block.
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).
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.
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);
}