I came across these two methods to concatenate strings:
Common part:
char* first= "First";
char* second = "Second";
char* both = malloc(strlen(first) + strlen(second) + 2);
Method 1:
strcpy(both, first);
strcat(both, " "); // or space could have been part of one of the strings
strcat(both, second);
Method 2:
sprintf(both, "%s %s", first, second);
In both cases the content of both
would be "First Second"
.
I would like to know which one is more efficient (I have to perform several concatenation operations), or if you know a better way to do it.
When concatenating three dynamic string values or less, use traditional string concatenation. When concatenating more than three dynamic string values, use StringBuilder . When building a big string from several string literals, use either the @ string literal or the inline + operator.
Doing N concatenations requires creating N new strings in the process. join() , on the other hand, only has to create a single string (the final result) and thus works much faster.
You concatenate strings by using the + operator. For string literals and string constants, concatenation occurs at compile time; no run-time concatenation occurs. For string variables, concatenation occurs only at run time.
Concatenation operators join multiple strings into a single string. There are two concatenation operators, + and & . Both carry out the basic concatenation operation, as the following example shows.
For readability, I'd go with
char * s = malloc(snprintf(NULL, 0, "%s %s", first, second) + 1);
sprintf(s, "%s %s", first, second);
If your platform supports GNU extensions, you could also use asprintf()
:
char * s = NULL;
asprintf(&s, "%s %s", first, second);
If you're stuck with the MS C Runtime, you have to use _scprintf()
to determine the length of the resulting string:
char * s = malloc(_scprintf("%s %s", first, second) + 1);
sprintf(s, "%s %s", first, second);
The following will most likely be the fastest solution:
size_t len1 = strlen(first);
size_t len2 = strlen(second);
char * s = malloc(len1 + len2 + 2);
memcpy(s, first, len1);
s[len1] = ' ';
memcpy(s + len1 + 1, second, len2 + 1); // includes terminating null
Don't worry about efficiency: make your code readable and maintainable. I doubt the difference between these methods is going to matter in your program.
Here's some madness for you, I actually went and measured it. Bloody hell, imagine that. I think I got some meaningful results.
I used a dual core P4, running Windows, using mingw gcc 4.4, building with "gcc foo.c -o foo.exe -std=c99 -Wall -O2".
I tested method 1 and method 2 from the original post. Initially kept the malloc outside the benchmark loop. Method 1 was 48 times faster than method 2. Bizarrely, removing -O2 from the build command made the resulting exe 30% faster (haven't investigated why yet).
Then I added a malloc and free inside the loop. That slowed down method 1 by a factor of 4.4. Method 2 slowed down by a factor of 1.1.
So, malloc + strlen + free DO NOT dominate the profile enough to make avoiding sprintf worth while.
Here's the code I used (apart from the loops were implemented with < instead of != but that broke the HTML rendering of this post):
void a(char *first, char *second, char *both)
{
for (int i = 0; i != 1000000 * 48; i++)
{
strcpy(both, first);
strcat(both, " ");
strcat(both, second);
}
}
void b(char *first, char *second, char *both)
{
for (int i = 0; i != 1000000 * 1; i++)
sprintf(both, "%s %s", first, second);
}
int main(void)
{
char* first= "First";
char* second = "Second";
char* both = (char*) malloc((strlen(first) + strlen(second) + 2) * sizeof(char));
// Takes 3.7 sec with optimisations, 2.7 sec WITHOUT optimisations!
a(first, second, both);
// Takes 3.7 sec with or without optimisations
//b(first, second, both);
return 0;
}
size_t lf = strlen(first);
size_t ls = strlen(second);
char *both = (char*) malloc((lf + ls + 2) * sizeof(char));
strcpy(both, first);
both[lf] = ' ';
strcpy(&both[lf+1], second);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With