Next: Truncating Strings while Copying, Previous: Copying Strings and Arrays, Up: String and Array Utilities [Contents][Index]
The functions described in this section concatenate the contents of a string or wide string to another. They follow the string-copying functions in their conventions. See Copying Strings and Arrays. ‘strcat’ is declared in the header file string.h while ‘wcscat’ is declared in wchar.h.
As noted below, these functions are problematic as their callers may have performance issues.
Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.
The strcat
function is similar to strcpy
, except that the
bytes from from are concatenated or appended to the end of
to, instead of overwriting it. That is, the first byte from
from overwrites the null byte marking the end of to.
An equivalent definition for strcat
would be:
char * strcat (char *restrict to, const char *restrict from) { strcpy (to + strlen (to), from); return to; }
This function has undefined results if the strings overlap.
As noted below, this function has significant performance issues.
Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.
The wcscat
function is similar to wcscpy
, except that the
wide characters from wfrom are concatenated or appended to the end of
wto, instead of overwriting it. That is, the first wide character from
wfrom overwrites the null wide character marking the end of wto.
An equivalent definition for wcscat
would be:
wchar_t * wcscat (wchar_t *wto, const wchar_t *wfrom) { wcscpy (wto + wcslen (wto), wfrom); return wto; }
This function has undefined results if the strings overlap.
As noted below, this function has significant performance issues.
Programmers using the strcat
or wcscat
functions (or the
strlcat
, strncat
and wcsncat
functions defined in
a later section, for that matter)
can easily be recognized as lazy and reckless. In almost all situations
the lengths of the participating strings are known (it better should be
since how can one otherwise ensure the allocated size of the buffer is
sufficient?) Or at least, one could know them if one keeps track of the
results of the various function calls. But then it is very inefficient
to use strcat
/wcscat
. A lot of time is wasted finding the
end of the destination string so that the actual copying can start.
This is a common example:
/* This function concatenates arbitrarily many strings. The last
parameter must be NULL
. */
char *
concat (const char *str, …)
{
va_list ap, ap2;
size_t total = 1;
va_start (ap, str);
va_copy (ap2, ap);
/* Determine how much space we need. */
for (const char *s = str; s != NULL; s = va_arg (ap, const char *))
total += strlen (s);
va_end (ap);
char *result = malloc (total);
if (result != NULL)
{
result[0] = '\0';
/* Copy the strings. */
for (s = str; s != NULL; s = va_arg (ap2, const char *))
strcat (result, s);
}
va_end (ap2);
return result;
}
This looks quite simple, especially the second loop where the strings are actually copied. But these innocent lines hide a major performance penalty. Just imagine that ten strings of 100 bytes each have to be concatenated. For the second string we search the already stored 100 bytes for the end of the string so that we can append the next string. For all strings in total the comparisons necessary to find the end of the intermediate results sums up to 5500! If we combine the copying with the search for the allocation we can write this function more efficiently:
char * concat (const char *str, …) { size_t allocated = 100; char *result = malloc (allocated); if (result != NULL) { va_list ap; size_t resultlen = 0; char *newp; va_start (ap, str); for (const char *s = str; s != NULL; s = va_arg (ap, const char *)) { size_t len = strlen (s); /* Resize the allocated memory if necessary. */ if (resultlen + len + 1 > allocated) { allocated += len; newp = reallocarray (result, allocated, 2); allocated *= 2; if (newp == NULL) { free (result); return NULL; } result = newp; } memcpy (result + resultlen, s, len); resultlen += len; } /* Terminate the result string. */ result[resultlen++] = '\0'; /* Resize memory to the optimal size. */ newp = realloc (result, resultlen); if (newp != NULL) result = newp; va_end (ap); } return result; }
With a bit more knowledge about the input strings one could fine-tune
the memory allocation. The difference we are pointing to here is that
we don’t use strcat
anymore. We always keep track of the length
of the current intermediate result so we can save ourselves the search for the
end of the string and use mempcpy
. Please note that we also
don’t use stpcpy
which might seem more natural since we are handling
strings. But this is not necessary since we already know the
length of the string and therefore can use the faster memory copying
function. The example would work for wide characters the same way.
Whenever a programmer feels the need to use strcat
she or he
should think twice and look through the program to see whether the code cannot
be rewritten to take advantage of already calculated results.
The related functions strlcat
, strncat
,
wcscat
and wcsncat
are almost always unnecessary, too.
Again: it is almost always unnecessary to use functions like strcat
.
Next: Truncating Strings while Copying, Previous: Copying Strings and Arrays, Up: String and Array Utilities [Contents][Index]