Many noob C programmer wonders, why strcat/strcpy return a value, if it's the same, as the 'destination' operand? Isn't it a bit redundant?
char *strcpy(char *dest, const char *src); char *strcat(char *dest, const char *src); void *memcpy(void *dest, const void *src, size_t n);
Mainly for chaining.
At the end of the day, this is used for string construction, without sprintf() and libraries like strbuf (I wrote about it in the C/C++ programming language notes).
This is the best macro I've seen so far. It allocate a buffer for three strings, concatenate them all and return a pointer to it:
#define COMBINETHREESTRINGS( FirstString, SecondString, ThirdString) strcat( strcat( strcpy( _alloca( strlen( FirstString) + strlen( SecondString) + strlen( ThirdString) + 1), FirstString), SecondString), ThirdString)
( WinNT-related-src/leaked-src/XPSP1/sdktools/compdir/compdir.c )
Add file extension:
szFileWSP = strcat( strcpy(szFileWSP , szBaseName ), ".WSP" );
...
szFileTMI = strcat( strcpy( szFileTMI, szBaseName ), ".TMI" );
( WinNT-related-src/leaked-src/Win2K3/sdktools/wst/wstune/wsreduce.c )
Concatenate 3 strings:
strcat(strcat(strcpy(rName.Ptr(), pNS), NAMESPACE_SEPARATOR_STR), pName);
...
strcat(strcat(strcpy(rName.Ptr(), pNS), NAMESPACE_SEPARATOR_STR), pclsname);
...
strcat(strcat(strcpy(rName.Ptr(), pNS), NAMESPACE_SEPARATOR_STR), pclsname);
( WinNT-related-src/leaked-src/Win2K3/com/netfx/src/clr/vm/tlbexport.cpp )
Construct a string and return the newly constructed buffer:
STATIC char *Cat1(char *s0, char *s1) {
return strcat(strcat(Cat0(s0), "\t"), s1);
} /* Cat1 */
STATIC char *Cat2(char *s0, char *s1, char *s2) {
return strcat(strcat(Cat1(s0, s1), ", "), s2);
} /* Cat2 */
STATIC char *Cat3(char *s0, char *s1, char *s2, char *s3) {
return strcat(strcat(Cat2(s0, s1, s2), ", "), s3);
} /* Cat3 */
( WinNT-related-src/leaked-src/Win2K3/base/mvdm/wow16/sherlock/disasm.c )
// operator+= -- CoolString concatenation of another string: x += y;
// Input: CoolString reference
// Output: CoolString object concatenated with CoolString contents
inline CoolString& CoolString::operator+= (const CoolString& s) {
return (strcat (*this, s));
}
( https://github.com/open-watcom/open-watcom-v2/blob/master/bld/plustest/cool/source/string.h )
Add file extensions:
size = strlen( fileprefix);
codefilename = MALLOC( size + 6, char );
strcat( strcpy( codefilename, fileprefix), "tab.c" );
headerfilename = MALLOC( size + 6, char );
strcat( strcpy( headerfilename, fileprefix), "tab.h" );
descfilename = MALLOC( size + 5, char );
strcat( strcpy( descfilename, fileprefix), ".out" );
actout = openw( codefilename );
defs( actout );
tokout = openw( headerfilename );
dump_header( tokout );
( https://github.com/open-watcom/open-watcom-v2/blob/master/bld/yacc/c/yacc.c )
Construct a string for environment:
env[0] = strcat(strcpy(env0, "TZ="), val);
( glibc/glibc-2.26/timezone/zdump.c )
Construct a string and pass it as an argument:
if( FileNameWild( argv[i], rxflag ) ) {
dirp = NULL;
} else if( IsSpecialRoot( argv[i] ) ) {
dirp = opendir( strcat( strcpy( filebuff, argv[i] ), "\\" ) );
} else {
dirp = opendir( argv[i] );
}
( https://github.com/open-watcom/open-watcom-v2/blob/master/bld/posix/src/ls/ls.c )
GetLine(rgb, strcat(strcpy(sbPrompt,GetMsg(P_defprompt)), " [nul.def]: "));
( WinNT-related-src/leaked-src/Win2K3/sdktools/link16/newcmd.c )
Construct a long buffer:
// FEXTRA
*output_curpos++ = 3; // LSB
*output_curpos++ = 0; // MSB
output_curpos += 3; // 3 bytes of data
// FNAME, null terminated filename
output_curpos += strlen(strcpy(output_curpos, "my filename"))+1;
// FCOMMENT, null terminated comment
output_curpos += strlen(strcpy(output_curpos, "my comment"))+1;
( WinNT-related-src/leaked-src/XPSP1/inetsrv/iis/svcs/w3/filters/compress/gzip/gzip.c )
Construct a long string:
for (n = 0; n < 7; ++n) {
pn->wday_abbr[n] = s;
s += strlen(strcpy(s, pt->wday_abbr[n])) + 1;
pn->wday[n] = s;
s += strlen(strcpy(s, pt->wday[n])) + 1;
}
for (n = 0; n < 12; ++n) {
pn->month_abbr[n] = s;
s += strlen(strcpy(s, pt->month_abbr[n])) + 1;
pn->month[n] = s;
s += strlen(strcpy(s, pt->month[n])) + 1;
}
( Win2K3/base/crts/crtw32/time/strftime.c )
Copy string and get its length at the same line:
rc = strlen(strncpy(outputString, "Unable to load msvcrt!__unDName", maxStringLength));
( WinNT-related-src/leaked-src/2000/private/sdktools/imagehlp/imagehlp.c )
Nested strcat/strcpy, pass the result to another function:
if (nameopt(strcat(strcat(strcpy(to, dir), "/"), from)) < 0) {
( QNX/trunk/utils/p/pax_qnx/pass.c )
Make copy of string and 'upper' it:
strupr( strcpy( node[i].fname, fname ) );
( https://github.com/open-watcom/open-watcom-v2/blob/master/bld/sdk/imgedit/c/ieopen.c )
Make copy of a string and do something with it:
slashify(strcpy(cmd, s), p);
( QNX/trunk/utils/g/gawk/pc/popen.c )
Allocate and copy buffer. This is the same as memdup() does:
PWSTR attrName = (PWSTR)memcpy(_alloca(len), newVal, len);
( WinNT-related-src/leaked-src/XPSP1/net/ias/providers/nap/cond/match.cpp )
/*
* We mark any token, that that equals to a known enumerator, as
* SYM_ENUM_CONST. The parser will change this for struct and union tags later,
* the only problem is struct and union members:
* enum e { a, b }; struct s { int a, b; }
* but in this case, the only effect will be, that the ABI checksums become
* more volatile, which is acceptable. Also, such collisions are quite rare,
* so far it was only observed in include/linux/telephony.h.
*/
#define _APP(T,L) do { \
cur_node = next_node; \
next_node = xmalloc(sizeof(*next_node)); \
next_node->next = cur_node; \
cur_node->string = memcpy(xmalloc(L+1), T, L+1); \
cur_node->tag = \
find_symbol(cur_node->string, SYM_ENUM_CONST, 1)?\
SYM_ENUM_CONST : SYM_NORMAL ; \
cur_node->in_source_file = in_source_file; \
} while (0)
( https://github.com/torvalds/linux/blob/master/scripts/genksyms/lex.l )
Allocate and copy string. This is the same as strdup() does:
return strcpy(alloc(strlen(str)+1), str);
( id/quake3-1.32b/lcc/etc/lcc.c )
Allocate string, construct it and return it, in the same line:
return(strcpy(alloc((unsigned)(strlen(string)+1)),string));
( WinNT-related-src/leaked-src/Win2K3/sdktools/vi/alloc.c )
How memdup() and strdup() can be implemented?
#define smbestrdup(p) strcpy(malloc(strlen(p) + 1), p)
( plan9/extr/sys/src/cmd/aquarela/smbfns.h )
# define zstrdup( x ) strcpy( zmalloc( strlen(x)+1 ), x )
( WinNT-related-src/leaked-src/XPSP1/shell/osshell/accesory/ratpak/ratpak.h )
/* Clone an object P of size S, with error checking. There's no need
for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
need for an arithmetic overflow check. */
void *
xmemdup (void const *p, size_t s)
{
return memcpy (xmalloc (s), p, s);
}
/* Clone STRING. */
char *
xstrdup (char const *string)
{
return xmemdup (string, strlen (string) + 1);
}
( QNX/trunk/ports/tar/lib/xmalloc.c )
Comments at Reddit, at lobste.rs

Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.