How concatenate a string and a const char?
string a = "hello ";
const char *b = "world";
a += b;
const char *C = a.c_str();
or without modifying a
:
string a = "hello ";
const char *b = "world";
string c = a + b;
const char *C = c.c_str();
Little edit, to match amount of information given by 111111.
When you already have string
s (or const char *
s, but I recommend casting the latter to the former), you can just "sum" them up to form longer string. But, if you want to append something more than just string you already have, you can use stringstream
and it's operator<<
, which works exactly as cout
's one, but doesn't print the text to standard output (i.e. console), but to it's internal buffer and you can use it's .str()
method to get std::string
from it.
std::string::c_str()
function returns pointer to const char
buffer (i.e. const char *
) of string contained within it, that is null-terminated. You can then use it as any other const char *
variable.
const char* concatenation
In your example one and two are char pointers, pointing to char constants. You cannot change the char constants pointed to by these pointers. So anything like:
strcat(one,two); // append string two to string one.
will not work. Instead you should have a separate variable(char array) to hold the result. Something like this:
char result[100]; // array to hold the result.
strcpy(result,one); // copy string one into the result.
strcat(result,two); // append string two to the result.
How do I concatenate const/literal strings in C?
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);
Why concatenation of two const char* is not allowed in C++?
With two literal strings, you can concatenate them, but you don't need any operator, just (optional) spaces. So
std::string s="hello" "world";
is allowed and the same as
std::string s="helloworld";
Actually, at parsing time, two literal strings are glued together as one. And this also applies to C and happens after preprocessing expansion.
This is phase 6 of the compilation process. Adjacent string literals are concatenated.
BTW, this only works with string literals. E.g.
std::string s1= ((1<2)?"hello":"goodbye") "world"; // wrong
std::string s2= ("ab")"cd"; // wrong
are both wrong.
You might also use the operator ""s
using std::literals::string_literals;
std::string s= "abcd"s + "ef"s;
but then both "abcd"s
and "ef"s
denote some constant std::string
-s and the +
applies to these.
Why c++ standard library developers decide not to reload"+" to implement a char* concatenation?
Then you would want to code
char* foo = (rand()%4)?"lucky":"unlucky";
char* bar = foo + "xy"; // wrong
and if such a +
was implemented, it would need to allocate heap memory (at runtime) à la strdup
and you would need to decide who and when would that be delete[]
or free
-d. BTW, as r0ng answered you cannot define an operator +
on pointer types. So the standard committee decision to not allow that is sane.
However if you replace char*
above twice with std::string
it works.
Concatenating integers to const char* strings
The type of a string literal like "file"
is char const[N]
(with a suitable N
) whic happily decays into a char const*
upon the first chance it gets. Although there is no addition defeined between T[N]
and int
, there is an addition defined between char const*
and int
: it adds the int
to the pointer. That isn't quite what you want.
You probably want to convert the int
into a suitable std::string
, combine this with the string literal you got, and get a char const*
from that:
load(("file" + std::to_string(i)).c_str());
Why can't I concat 2 const char* to a std::string?
The technical reasons for not having such an operator are centred around ownership (what would own this operator? std::string
, the global namespace, or something else), the fact that adding two const char*
pointers makes no sense, and other issues centred around the properties of read-only NUL-terminated character literals.
"Hello" + " World"
knows nothing about what it's about to be assigned to. The use of the +
requires the const char[]
literals to decay to const char*
pointers. Adding two pointers makes no sense at all and so modern compilers will issue a diagnostic stating that +
is not defined for const char[]
types.
"Hello" " World"
is the C-idiomatic string literal concatenation syntax. That's been around since the 1970s and helps folk write long strings when there were only 80 or so characters visible per line of code.
hello + " World"
is using the overloaded +
operator on std::string
. That's because hello
is a std::string
.
From C++14 onwards you could exploit user defined literals with
std::string str = "Hello"s + " World";
or even
std::string str = ""s + "Hello" + " World";
Note the suffixed s
.
Is it possible to concatenate two strings of type `const char *` at compile time?
Here is a quick compile time string class:
template<std::size_t N>
struct ct_str
{
char state[N+1] = {0};
constexpr ct_str( char const(&arr)[N+1] )
{
for (std::size_t i = 0; i < N; ++i)
state[i] = arr[i];
}
constexpr char operator[](std::size_t i) const { return state[i]; }
constexpr char& operator[](std::size_t i) { return state[i]; }
constexpr explicit operator char const*() const { return state; }
constexpr char const* data() const { return state; }
constexpr std::size_t size() const { return N; }
constexpr char const* begin() const { return state; }
constexpr char const* end() const { return begin()+size(); }
constexpr ct_str() = default;
constexpr ct_str( ct_str const& ) = default;
constexpr ct_str& operator=( ct_str const& ) = default;
template<std::size_t M>
friend constexpr ct_str<N+M> operator+( ct_str lhs, ct_str<M> rhs )
{
ct_str<N+M> retval;
for (std::size_t i = 0; i < N; ++i)
retval[i] = lhs[i];
for (std::size_t i = 0; i < M; ++i)
retval[N+i] = rhs[i];
return retval;
}
friend constexpr bool operator==( ct_str lhs, ct_str rhs )
{
for (std::size_t i = 0; i < N; ++i)
if (lhs[i] != rhs[i]) return false;
return true;
}
friend constexpr bool operator!=( ct_str lhs, ct_str rhs )
{
for (std::size_t i = 0; i < N; ++i)
if (lhs[i] != rhs[i]) return true;
return false;
}
template<std::size_t M, std::enable_if_t< M!=N, bool > = true>
friend constexpr bool operator!=( ct_str lhs, ct_str<M> rhs ) { return true; }
template<std::size_t M, std::enable_if_t< M!=N, bool > = true>
friend bool operator==( ct_str, ct_str<M> ) { return false; }
};
template<std::size_t N>
ct_str( char const(&)[N] )->ct_str<N-1>;
you can use it like this:
template <class T>
constexpr auto get_arithmetic_size()
{
if constexpr (sizeof(T)==1)
return ct_str{"1"};
if constexpr (sizeof(T)==2)
return ct_str{"2"};
if constexpr (sizeof(T)==4)
return ct_str{"4"};
if constexpr (sizeof(T)==8)
return ct_str{"8"};
if constexpr (sizeof(T)==16)
return ct_str{"16"};
}
template <class T, std::enable_if_t<std::is_arithmetic<T>{}, bool> = true>
constexpr auto make_type_name()
{
if constexpr (std::is_signed<T>{})
return ct_str{"int"} + get_arithmetic_size<T>();
else
return ct_str{"uint"} + get_arithmetic_size<T>();
}
which leads to statements like:
static_assert(make_type_name<int>() == make_type_name<int32_t>());
passing.
Live example.
Now one annoying thing is that the length of the buffer is in the type system. You could add a length
field, and make N
be "buffer size", and modify ct_str
to only copy up to length
and leave the trailing bytes as 0
. Then override common_type
to return the max N
of both sides.
That would permit you do pass ct_str{"uint"}
and ct_str{"int"}
in the same type of value and make the implementation code a bit less annoying.
template<std::size_t N>
struct ct_str
{
char state[N+1] = {0};
template<std::size_t M, std::enable_if_t< (M<=N+1), bool > = true>
constexpr ct_str( char const(&arr)[M] ):
ct_str( arr, std::make_index_sequence<M>{} )
{}
template<std::size_t M, std::enable_if_t< (M<N), bool > = true >
constexpr ct_str( ct_str<M> const& o ):
ct_str( o, std::make_index_sequence<M>{} )
{}
private:
template<std::size_t M, std::size_t...Is>
constexpr ct_str( char const(&arr)[M], std::index_sequence<Is...> ):
state{ arr[Is]... }
{}
template<std::size_t M, std::size_t...Is>
constexpr ct_str( ct_str<M> const& o, std::index_sequence<Is...> ):
state{ o[Is]... }
{}
public:
constexpr char operator[](std::size_t i) const { return state[i]; }
constexpr char& operator[](std::size_t i) { return state[i]; }
constexpr explicit operator char const*() const { return state; }
constexpr char const* data() const { return state; }
constexpr std::size_t size() const {
std::size_t retval = 0;
while(state[retval]) {
++retval;
}
return retval;
}
constexpr char const* begin() const { return state; }
constexpr char const* end() const { return begin()+size(); }
constexpr ct_str() = default;
constexpr ct_str( ct_str const& ) = default;
constexpr ct_str& operator=( ct_str const& ) = default;
template<std::size_t M>
friend constexpr ct_str<N+M> operator+( ct_str lhs, ct_str<M> rhs )
{
ct_str<N+M> retval;
for (std::size_t i = 0; i < lhs.size(); ++i)
retval[i] = lhs[i];
for (std::size_t i = 0; i < rhs.size(); ++i)
retval[lhs.size()+i] = rhs[i];
return retval;
}
template<std::size_t M>
friend constexpr bool operator==( ct_str lhs, ct_str<M> rhs )
{
if (lhs.size() != rhs.size()) return false;
for (std::size_t i = 0; i < lhs.size(); ++i)
if (lhs[i] != rhs[i]) return false;
return true;
}
template<std::size_t M>
friend constexpr bool operator!=( ct_str lhs, ct_str<M> rhs )
{
if (lhs.size() != rhs.size()) return true;
for (std::size_t i = 0; i < lhs.size(); ++i)
if (lhs[i] != rhs[i]) return true;
return false;
}
};
template<std::size_t N>
ct_str( char const(&)[N] )->ct_str<N-1>;
The function implementations now become:
template <class T>
constexpr ct_str<2> get_arithmetic_size()
{
switch (sizeof(T)) {
case 1: return "1";
case 2: return "2";
case 4: return "4";
case 8: return "8";
case 16: return "16";
}
}
template <class T, std::enable_if_t<std::is_arithmetic<T>{}, bool> = true>
constexpr auto make_type_name()
{
constexpr auto base = std::is_signed<T>{}?ct_str{"int"}:ct_str{"uint"};
return base + get_arithmetic_size<T>();
}
which is a lot more natural to write.
Live example.
How to concatenate const char* strings in c++ with no function calls?
First, there is nothing null
terminated, but the zero terminated. All char* strings in C end with '\0'
.
When you in code do something like this:
char *name="Daniel";
compiler will generate a string that has a contents:
Daniel\0
and will initialize name
pointer to point at it at a certain time during program execution depending on the variable context (member, static, ...).
Appending ANYTHING to the name
won't work as you expect, since memory pointed to by name
isn't changeable, and you'll probably get either access violation error or will overwrite something else.
Having
const char* copyOfTheName = name;
won't create a copy of the string in question, it will only have copyOfTheName
point to the original string, so having
copyOfTheName[6]='A';
will be exactly as
name[6]='A';
and will only cause problems to you.
Use std::strcat
instead. And please, do some investigating how the basic string operations work in C.
Related Topics
Why Openmp Under Ubuntu 12.04 Is Slower Than Serial Version
Std::Vector Calling Destructor Multiple Times During Push_Back
C++ Inheritance and Name Hiding
C++ Logon Task Schedule Error: No Mapping Between Account Names and Security Ids Was Done
Convert Shared Library to Static Library
How to Mark a Struct Template as Friend
Using Std::Make_Unique with a Custom Deleter
Why Does C++11 Not Support Anonymous Structs, While C11 Does
How to Convert a Byte Array into Double in C
Can You Start a Class Name with a Numeric Digit
Seeking Code Stub Generator (From Header Files)