How do I concatenate const/literal strings in C?

1,218,330

Solution 1

In C, "strings" are just plain char arrays. Therefore, you can't directly concatenate them with other "strings".

You can use the strcat function, which appends the string pointed to by src to the end of the string pointed to by dest:

char *strcat(char *dest, const char *src);

Here is an example from cplusplus.com:

char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");

For the first parameter, you need to provide the destination buffer itself. The destination buffer must be a char array buffer. E.g.: char buffer[1024];

Make sure that the first parameter has enough space to store what you're trying to copy into it. If available to you, it is safer to use functions like: strcpy_s and strcat_s where you explicitly have to specify the size of the destination buffer.

Note: A string literal cannot be used as a buffer, since it is a constant. Thus, you always have to allocate a char array for the buffer.

The return value of strcat can simply be ignored, it merely returns the same pointer as was passed in as the first argument. It is there for convenience, and allows you to chain the calls into one line of code:

strcat(strcat(str, foo), bar);

So your problem could be solved as follows:

char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);

Solution 2

Avoid using strcat in C code. The cleanest and, most importantly, the safest way is to use snprintf:

char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);

Some commenters raised an issue that the number of arguments may not match the format string and the code will still compile, but most compilers already issue a warning if this is the case.

Solution 3

Strings can also be concatenated at compile time.

#define SCHEMA "test"
#define TABLE  "data"

const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry =               // include comments in a string
    " SELECT * "                // get all fields
    " FROM " SCHEMA "." TABLE   /* the table */
    " WHERE x = 1 "             /* the filter */ 
                ;

Solution 4

Folks, use strncpy(), strncat(), or snprintf().
Exceeding your buffer space will trash whatever else follows in memory!
(And remember to allow space for the trailing null '\0' character!)

Solution 5

Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.

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

void example(const char *header, const char **words, size_t num_words)
{
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
    char *message = (char*) malloc(message_len);
    strncat(message, header, message_len);

    for(int i = 0; i < num_words; ++i)
    {
       message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
       message = (char*) realloc(message, message_len);
       strncat(strncat(message, ";", message_len), words[i], message_len);
    }

    puts(message);

    free(message);
}
Share:
1,218,330
Per Knytt
Author by

Per Knytt

I am a programmer always looking to learn more.

Updated on May 14, 2021

Comments

  • Per Knytt
    Per Knytt about 3 years

    I'm working in C, and I have to concatenate a few things.

    Right now I have this:

    message = strcat("TEXT ", var);
    
    message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
    

    Now if you have experience in C I'm sure you realize that this gives you a segmentation fault when you try to run it. So how do I work around that?

  • unwind
    unwind over 15 years
    ... but without the needless and confusing parenthesis to the sizeof operator. Those are only needed when you want the size of an actual type, not of an object. Pet peeve alert, sorry.
  • Alex B
    Alex B over 15 years
    This is arguably the best way to find out the size of the buffer, unless you are given a pointer. If you have a pointer, you will be passing the length of the buffer it points to with it.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 15 years
    Checkers, he was talking about the parentheses around "buf" of the sizeof argument. they are not required if the argument is an expression. But i don't understand why you are downvoted. i think your answer is the best of all, even though it is c99. (maybe because of that they disagree! lamers!) +1
  • Alex B
    Alex B over 15 years
    Oh, reading comprehension -1. But anyway, I stand by my answer.
  • Mr.Ree
    Mr.Ree over 15 years
    sizeof() only works here for char buf[...]. NOT for char * buf = malloc(...). There aren't many differences between arrays and pointers, but this is one of them!
  • Alex B
    Alex B over 15 years
    Yes, hence my comment about dynamically allocated buffers.
  • plinth
    plinth over 15 years
    Would you put "Be very careful that..." in bold, please? This can't be stressed enough. Misuse of strcat, strcpy, and sprintf are the heart of unstable/insecure software.
  • Graeme Perrow
    Graeme Perrow over 15 years
    Not only should you remember to allow space for the NULL character, you need to remember to add the NULL character. strncpy and strncat don't do that for you.
  • unwind
    unwind over 15 years
    Uh? strncpy() and strncat() sure add the terminating character. In fact, they add too many. At least as long as there's space left in the buffer, which is a huge trap with these calls. Not recommended.
  • quinmars
    quinmars over 15 years
    @unwind, I think the point of Graeme is that if the buffer is too small, strncpy or strncat will not add the terminating '\0'.
  • Mr.Ree
    Mr.Ree over 15 years
    if n < strlen()+1, no null is added. if n==strlen()+1, one null is added. if n>strlen()+1 many nulls are added. It's called PROGRAMMING.
  • Alex B
    Alex B over 15 years
    Even better, prefer OpenBSD's strlcpy, strlcat (easy to port into your own project).
  • quinmars
    quinmars over 15 years
    Right, I prefer strl*, too. But in this case I think your snprintf proposal is the best way.
  • user2522201
    user2522201 over 15 years
    "static string" and "allocate your own buffer" may be misleading as the former could be interpreted to mean "static string buffer" and the latter to indicate dynamical allocation. +1 if you change to "You can never use a string literal as a buffer, you must always use your own buffer" or similar.
  • user2522201
    user2522201 over 15 years
    snprintf is good, strncpy/strncat is the worst possible recommendation, strlcpy/strlcat is much better.
  • Brian
    Brian over 15 years
    Warning: As written, this code will leave a giant, gaping hole in your code for buffer overflow exploits.
  • Brian R. Bondy
    Brian R. Bondy over 15 years
    There is no buffer overflow exploit possible in the above example. And yes I agree in general I wouldn't use the above example for undetermined string lengths of foo and bar.
  • MarkD
    MarkD over 15 years
    What happens if var/foo/bar has more than 1000 characters? >:)
  • crazy_in_love
    crazy_in_love over 15 years
    Also, he is trying to perform concatenation. Concatenating using snprintf() is a BIG no no.
  • paxdiablo
    paxdiablo over 15 years
    Then you will get a buffer overflow, which you can add code to check for beforehand (say, with strlen). But the purpose of a code snippet is to show how something works without polluting it with too much extra code. Otherwise I'd be checking lengths, whether var/foo/bar was null, etc.
  • quinmars
    quinmars over 15 years
    @Leonardo, can you tell use why?
  • Christian.K
    Christian.K over 15 years
    Well, there is some risk that you add another, say, "str5" and forget an additional "%s" in the format string - or the other way around. Will only crash on you (if you are lucky) on runtime. Besides it seems a bit overkill given the safe alternatives of "strcat".
  • dolmen
    dolmen over 13 years
    Don't use strcat multiple times! strcat has to check all the previous bytes (searching for '\0') you already concatenated. This is useless processing.
  • Alex B
    Alex B over 13 years
    @Christian.K ah, but a decent compiler will warn you if you do this.
  • Mooing Duck
    Mooing Duck over 12 years
    <string.h> is C++ style. You want "string.h". You also calculate strlen(s1) twice, which isn't needed. s3 should be totalLenght+1 long.
  • Lightness Races in Orbit
    Lightness Races in Orbit over 12 years
    @paxdiablo: But you didn't even mention it, in an answer to a question where it would appear to need mentioning. That makes your answer dangerous. You also didn't explain why this code is better than the OP's original code, except for the myth that it "achieves the same result as your original" (then what would be the point? the original was broken!), so the answer is also incomplete.
  • Lightness Races in Orbit
    Lightness Races in Orbit over 12 years
    @MrRee: The differences between pointers and arrays are vast and complete! It's in how you use them that does not always differ. Also, pointers and dynamic allocation are really orthogonal concepts.
  • sbi
    sbi over 12 years
    @MooingDuck: "string.h" is nonsense.
  • Nils
    Nils over 12 years
    I haven't used C-style strings for a while. Feel free to post a fixed version.
  • Keith Thompson
    Keith Thompson over 12 years
    @MooingDuck: That's incorrect. #include <string.h> is correct C. Use angle brackets for standard and system headers (including <string.h>), quotation marks for headers that are part of your program. (#include "string.h" will happen to work if you don't have your own header file by that name, but use <string.h> anyway.)
  • Keith Thompson
    Keith Thompson over 12 years
    Note that this depends on C99-specific features: mixing declarations and statements, and variable-length arrays (VLAs). Note also that VLAs provide no mechanism to detect or handle allocation failures; if there isn't enough room to allocate a VLA, your program's behavior is undefined.
  • Nils
    Nils over 12 years
    Posted a fixed version, plz reconsider your voting.
  • Keith Thompson
    Keith Thompson over 12 years
    Don't use strncpy(). It's not a "safer" version of strcpy(). The target character array may be needlessly padded with extra '\0' characters, or worse, it may be left unterminated (i.e., not a string). (It was designed for use with a data structure that's rarely used anymore, a character array padded to the end with zero or more '\0' characters.)
  • Keith Thompson
    Keith Thompson over 12 years
    The type of "TEXT" is char[5], not const char*. It decays to char* in most contexts. For backward compatibility reasons, string literals are not const, but attempting to modify them results in undefined behavior. (In C++, string literals are const.)
  • Keith Thompson
    Keith Thompson over 12 years
    You could safely use strcat rather than strncat, since you've already guaranteed that the target is big enough.
  • Nils
    Nils over 12 years
    @KeithThompson agree, switched to just strcpy for now.
  • sbi
    sbi over 12 years
    @KeithThompson: It's now worthy an upvote, turned my -1 into a +1. (This answer was "inspired" by a discussion about C vs. C++ string handling in the C++ chat room. I think, Nils, that with this debacle you have quite effectively demonstrated your opponents' POV. :^>)
  • peter.slizik
    peter.slizik almost 12 years
    To second @dolmen, Joel Spolsky has written quite elaborate article on the issue. Should be a mandatory reading. ;-)
  • Per Johansson
    Per Johansson almost 11 years
    You should return char *, not const char *. The return value will need to be passed to free.
  • Calmarius
    Calmarius over 10 years
    Unfortunately asprintf is only a GNU extension.
  • Oleg Vazhnev
    Oleg Vazhnev about 10 years
    what type str1 str2 should have? Can I use std::string or only char* is allowed?
  • Alex B
    Alex B about 10 years
    @javapowered %s only expects char*.
  • Jonathan Leffler
    Jonathan Leffler about 10 years
    One of my pet peeves is people like @unwind who insist on the pointless distinction between sizeof(x) and sizeof x. The parenthesized notation always works and the unparenthesized notation only works sometimes, so always use the parenthesized notation; it is a simple rule to remember and is safe. This gets into a religious argument — I've been involved in discussions with those who object before — but the simplicity of 'always use parentheses' outweighs any merit to not using them (IMNSHO, of course). This is presented for balance.
  • stackPusher
    stackPusher almost 9 years
    agreed. lets not forget that sizeof should be interpreted as a function call. And that sizeof(x+1) and sizeof(x) + 1 are very different things
  • paxdiablo
    paxdiablo about 8 years
    Have hopefully addressed your concerns, @PreferenceBean, though in a less timely manner than ideal :-) Let me know if you still have a problem with the answer, and I'll improve it further.
  • Liviu
    Liviu almost 8 years
    I foresee buffer overflow, I see you allocated strlen(str1) + strlen(str2), but you write strlen(str1) + strlen(str2) + 1 characters. So can you really write your own function?
  • Liviu
    Liviu almost 8 years
    Wow! You never free the memory, nasty, nasty! return buffer; free(buffer);
  • Liviu
    Liviu almost 8 years
    BTW, sizeof(char) == 1 (Besides, there are other more subtle errors ...) Can you see now why you don't have to write your own function ?
  • Donald Duck
    Donald Duck almost 8 years
    @Liviu I do free the memory at the line free(buffer);.
  • Liviu
    Liviu almost 8 years
    @Duck you free the memory after exiting form the function ... so you do not free it
  • Liviu
    Liviu almost 8 years
    char* mycat = strcat_const("Hello ","world"); free(mycat); There is a difference, isn't it ?
  • Donald Duck
    Donald Duck almost 8 years
    @Liviu Does that change anything? In that example, I think it would do the printf("%s",strcat_const("Hello ","world")); and then free the memory, so if you put more after that in the main() function it will free the memory before. Tell me if I'm wrong.
  • Liviu
    Liviu almost 8 years
    free(buffer); after return buffer; is never executed, see it in a debugger ;) I see now: yes, you have to free the memory in the main function
  • Liviu
    Liviu almost 8 years
    My point is: you can play with fire (re-writing known functions) in your own project, but never in real life.
  • Donald Duck
    Donald Duck almost 8 years
    @Liviu I edited it so that there isn't any memory leak but it only supports a limited number of characters.
  • Liviu
    Liviu almost 8 years
    What if strlen(str1) >= MAX_STRING_LENGTH?
  • Liviu
    Liviu almost 8 years
    "No null-character is implicitly appended at the end of destination if source is longer than num." cplusplus.com/reference/cstring/strncpy
  • Liviu
    Liviu almost 8 years
    buffer[strlen(buffer)] = '\0'; Is there something strange in this line ? Guess how strlen works ;) ! I'll be back on Monday, have a nice week-end!
  • Liviu
    Liviu almost 8 years
    I think that should work, I'll re-watch when I'm back! You can add MAX_STRING_LENGTH as a parameter to strcat_const (with another name, of course).
  • Liviu
    Liviu almost 8 years
    It is a disaster :(, you return the address of a stack variable (the buffer variable is defined only inside strcat_const). I think you should stay with the dynamic allocation solution
  • 12431234123412341234123
    12431234123412341234123 about 7 years
    This will end in a endless loop when num_words>INT_MAX, maybe you should use size_t for i
  • bzim
    bzim over 6 years
    Actually, string literals can be concatenated by just putting them side by side. e.g. const char *str = "these" "strings" "are" "concatenated";.
  • user3150128
    user3150128 almost 6 years
    In strncpy and strncat this n is the max number of characters to copy, not the size of the target buffer. This and the non-terminated strings in case of truncation, and the different truncation handling on different platforms make it dangerous too. Please consider strlcpy and strlcat. See also my little article on this topic: gergap.wordpress.com/2013/04/05/…
  • Danijel
    Danijel over 3 years
    Shouldn't initial char buffer be initialized to zeros: char str[80] = {0};? This way you get a nice null-terminated string.
  • aerijman
    aerijman over 3 years
    1- Best answer, neat!. 2- For me sprintf works without sizeof as second argument. I found int sprintf(char *str, const char *format, ...) in tutorialspoint.com/c_standard_library/c_function_sprintf.htm
  • Andrew Koster
    Andrew Koster almost 3 years
    Why snprintf? Why not sprintf instead?