36

Is there a better way to concatenate multiple strings together in c other than having multiple calls to strcat() all in a row, like below?

char prefix[100] = "";
strcat(prefix, argv[0]);
strcat(prefix, ": ");
strcat(prefix, cmd_argv[0]);
strcat(prefix, ": ");
strcat(prefix, cmd_argv[1]);
perror(prefix);
4
  • 15
    This is a case of Shlemiel the Painter. Commented May 4, 2011 at 21:14
  • 1
    Beware of Microsoft's _snprintf which doesn't guarantee null termination of the destination buffer. Commented May 4, 2011 at 21:26
  • 1
    I like how it's actually done in the question with strcat. Commented Sep 28, 2020 at 2:04
  • Was the question also on the best practice, instead of just technical approach? How to manage a workflow of decision => modification, multiple times on a large string? (performance and memory concern) Commented May 16, 2023 at 15:51

8 Answers 8

34
sprintf(prefix,"%s: %s: %s",argv[0],cmd_argv[0],cmd_argv[1]);

Or snprintf to prevent buffer overruns.

Sign up to request clarification or add additional context in comments.

2 Comments

Definitely change it to snprintf. sprintf simply should not be used in modern code.
Or we could over load the + operator and make it similar to java.
19

snprintf would be the best and easiest to use option, though it may not be "fast". You didn't state what your criteria was. Simplicity is definitely this, though:

snprintf(prefix, sizeof(prefix), "%s: %s: %s", argv[0], cmd_argv[0], cmd_argv[1]);

Comments

7

I would use sprintf() like others have suggested, but this is for completeness:

If you have stpcpy(), then you can do:

char prefix[100] = "";
stpcpy(stpcpy(stpcpy(sptcpy(stpcpy(prefix, argv[0]), ": "),
        cmd_argv[0]), ": "), cmd_argv[1]);
perror(prefix);

The convenience with stpcpy() is that it can be "chained", as above. Also, since stpcpy() returns a pointer to the end of the resultant string, subsequent stpcpy() calls don't need to go through the old data again and again. So, it is more efficient than multiple strcat()s and probably more efficient than sprintf(). stpcpy() is POSIX:2008.

Comments

6

I might take a rep hit for this, but what the heck. The worst thing that can happen is I'll learn something.

I don't really use C these days, and I don't typically use C-style strings in C++. But one idea I have is to write a modified strcpy() that returns the end of the string:

char* my_strcpy(char*dest, const char* src)
{
    while ((*dest = *src++))
        ++dest;
    return dest;
}

Now Shlemiel can bring his bucket along with him:

char prefix[100] = "";
char* bucket = my_strcpy(prefix, argv[0]);
bucket = my_strcpy(bucket, ": ");
bucket = my_strcpy(bucket, cmd_argv[0]);
bucket = my_strcpy(bucket, ": ");
bucket = my_strcpy(bucket, cmd_argv[1]);
perror(prefix);

I haven't tested this. Comments?

EDIT: Removed the unnecessary my_strcat() function. Also it turns out to be the same as stpcpy(), which is apparently part of POSIX as of 2008. See http://www.manpagez.com/man/3/stpcpy/.

4 Comments

my_strcpy() is known as stpcpy() in POSIX - and you don't need my_strcat(), since my_strcpy() would work just as well (since you already have a pointer to the end of the string).
@caf: I thought of the my_strcat() point after I posted, but I didn't know about stpcpy(). See, I did learn something!
@caf: Actually, it appears stpcpy() is not POSIX: "The stpcpy() function conforms to no standard." (from manpagez.com/man/3/stpcpy)
@caf: After further review, it was recently added to POSIX: stackoverflow.com/questions/5826773/…. I guess the man pages haven't caught up yet.
4

If you're trying to build a string from other strings (which your example suggests), then you can use snprintf.

char prefix[100] = "";
snprintf( prefix, sizeof(prefix), "%s: %s: %s", argv[0], cmd_argv[0], cmd_argv[1]);

If you're trying to do concatenation of an existing string, where you can't use the format approach, then you're probably stuck with multiple calls to strcat, although I'd strongly suggest that you might want to consider using strncat instead and checking to ensure you don't have buffer overruns.

Comments

3

Assuming you have a char[fixed_size] as posted, rather than a char*, you can use a single, creative macro to do it all at once with a cout-like ordering rather than the disjointed printf style format. If you are working with embedded systems, this method will allow you to leave out the large printf family of functions like snprintf() (This keeps dietlibc from complaining too) and doesn't even require malloc() or any functions from <string.h>.

#include <unistd.h> //for write
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
    char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
    const char *s, \
    *a[] = { __VA_ARGS__,NULL}, \
    **ss=a; \
    while((s=*ss++)) \
         while((*s)&&(++offset<(int)sizeof(buf))) \
            *bp++=*s++; \
    if (offset!=sizeof(buf))*bp=0; \
}while(0)

char buf[100];
int len=0;
strcpyALL(buf,len, argv[0],": ", cmd_argv[0],": ",cmd_argv[1]);
if (len==sizeof(buf))write(2,"error\n",6);
else write(1,buf,len); 
  • Note 1, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
  • Note 2, if you are using a shared library or are already using a printf style function anywhere in your statically built program, the only reason not to use snprintf() (since the compiled code would be larger with this method) would be that since it is inlined and doesn't call any external functions, so it should be relatively fast.

Comments

2

you can use snprintf function

char prefix[100];
snprintf(prefix, 100, "%s: %s: %s", argv[0], cmd_argv[0], cmd_argv[1]);

1 Comment

better not to use %s for ":" you can simply put the : instead of %s
1

Couldn't you use a Macro.

#include <stdio.h>
#include <string.h>

#define a argv[0]
#define b argv[1]
#define c argv[2]
#define strcat1(a,b,c) strcat(prefix, a);\
                       strcat(prefix, ": ");\
                       strcat(prefix, b);\
                       strcat(prefix, ": ");\
                       strcat(prefix, c);\
                       perror(prefix);\



int main(int argc, char *argv[]){
    char prefix[100] = "";
    strcat1(a,b,c);
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.