Concatenating strings in C, which method is more efficient?
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);
They should be pretty much the same. The difference isn't going to matter. I would go with sprintf
since it requires less code.