How to concatenate strings using + operator - c++

Why one is allowed while another produce error. Anyone who can explain.
#include<string>
using namespace std;
int main()
{
string s3 = "Why";
string s11 = "hello" + " , " + s3; // It gives error
string s11 = s3 + " , " +"hello" ; // This works fine.
}

Due the operator precedence, the line
string s11 = "hello" + " , " + s3;
is processed as
string s11 = ("hello" + " , " ) + s3;
The sub-expression "hello" + " , " is not legal.
The first term is of type char const [6] (an array of 6 char const) and the second term is of type char const [4] (an array of 4 char const).
There is no + operator between the two. That's why it's a compiler error.
The second line
string s11 = s3 + " , " + "hello"
is processed as
string s11 = (s3 + " , ") + "hello"
The sub-expression s3 + " , " is valid since there is an overload of the operator+ that supports that operation. The sub-expression evaluates to a std::string. Hence, the subsequent + "hello" is also a supported operation.

"hello" is a string literal and its type is array of characters (char[6]). The operator+ is defined only for std::string. You can use the udl s to make it std::string:
int main()
{
using namespace std::string_literals;
std::string s3 = "Why"s;
std::string s11 = "hello"s + " , "s + s3;
std::string s12 = s3 + " , "s +"hello";
}

Related

Returning char * instead of string

How may I correct the following code in C++11:
const char *what() const noexcept override {
return "Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
std::to_string(mat1_width)
+ ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")";
}
As you can see I'm returning string instead of const char* but won't that be converrted automatically? and how to fix that?
Note: I want something to look like c++ code and not c using sprintf for example
but won't that be converrted automatically?
No.
and how to fix that?
Store the string as a member, and call c_str() in what. Example:
struct descriptive_name : std::exception {
std::string msg;
descriptive_name(
int mat1_width,
int mat1_height,
int mat2_width,
int mat2_height)
: msg(
"Mtm matrix error: Dimension mismatch: ("
+ std::to_string(mat1_height)
+ ","
+ std::to_string(mat1_width)
+ ") ("
+ std::to_string(mat2_height)
+ ","
+ std::to_string(mat2_width)
+ ")"
)
{}
const char *what() const noexcept override {
return msg.c_str();
}
};
Even better: Inherit from std::runtime_error, don't override what, and initialise the base class with the message string. Example:
struct descriptive_name : std::runtime_error {
descriptive_name(
int mat1_width,
int mat1_height,
int mat2_width,
int mat2_height)
: std::runtime_error(
"Mtm matrix error: Dimension mismatch: ("
+ std::to_string(mat1_height)
+ ","
+ std::to_string(mat1_width)
+ ") ("
+ std::to_string(mat2_height)
+ ","
+ std::to_string(mat2_width)
+ ")"
)
{}
};
It's not as simple because you are returning a temporary object which you are trying to convert into a pointer. You CAN do that by using
const char *what() const noexcept override {
return ("Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
std::to_string(mat1_width)
+ ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")").c_str();
}
but after converting the object will be destroyed and this will result in the actual data being deleted. Instead you can just copy the data.
const char* what()
{
std::string temp = "Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
std::to_string(mat1_width)
+ ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")";
char * p = new char[temp.size()+1]{};
strcpy(p,temp.data());
return p;
}
Just note that this is inefficient since you are creating and destroying and object and there is an extra copy which might be slow. Also you must remember to delete the char* after using this function.

Printing character after addition as string in C++

I am trying to print 'd' as string in C++.
string s = to_string((char)('a'+ 3));
cout << s << endl;
Expected Output: "d"
Actual Output: "100"
I am unable to understand this behavior.
Any help would be highly appreciated.
std::to_string is a function to convert integer or floating point values to strings. You shouldn't use it in this situation.
Use simply
std::cout << 'a' + 3 << std::endl;
Or
char c = 'a' + 3;
std::cout << c << std::endl;
Or if you really want the result to be saved as string:
std::string s = std::string{'a' + 3};
std::cout << s << std::endl;
What you need is
std::string s( 1, 'a'+ 3 );
or
std::string s;
s += 'a'+ 3;
or for example like
std::string s( 1, 'a' );
s.back() += 3;
(there are several ways to get the expected result)
As for this declaration
string s = to_string((char)('a'+ 3));
then the expression ( char )('a' + 3 ) is implicitly converted to an int type (due to integral promotions an the type of the argument of the selected overloaded function std::to_string) that is represented as a string after the call of std::to_string..

'+' cannot add two pointers, but just printing an int and an explicit string?

I am trying to use an array to keep track of the totals of different types of items (up to 50 types). When I want to print the totals out, I get an error saying "'+' cannot add two pointers." I'm thinking the problem is with my totals array somehow, but I can't figure it out. Below is a sample of my code:
string printSolution()
{
int totals[50];
string printableSolution = "";
for (int k = 0; k < itemTypeCount; k++)
{
totals[k] = 0;
}
for (int i = 0; i < itemCount; i++)
{
totals[items[i].typeCode]++;
}
for (int a = 0; a < itemTypeCount; a++)
{
printableSolution.append("There are " + totals[a] + " of Item type " + (a + 1) + ". \n");
}
}
The string literals "Foo" are of const char*, i.e. pointer type.
To understand what happens with:
"There are " + totals[a] + " of Item type " + (a + 1) + ". \n"
Let's look at an expression:
"0123456789" + 5
This actually just offsets 5 bytes from the start, so becomes:
"56789"
So an expression:
"0123456789" + 5 + "foo"
becomes:
"56789" + "foo"
as pointers, and this is not defined.
What you really want is string concatenation; this can be achieved using std::string.
We can write:
std::string("56789") + "foo"
and this generates a std::string with value: "56789foo" as you desire.
But:
std::string("0123456789") + 5
is also not defined. You need to use:
std::string("0123456789") + std::to_string(5)
So, finally you want:
std::string("There are ") + std::to_string(totals[a]) + " of Item type " + std::to_string(a + 1) + ". \n"
Note now you do not need to explitly convert all the "" to std:string, as once you have one implicit type conversion will take care of the other operand in operator+. However, adding them would do no harm:
std::string("There are ") + std::to_string(totals[a]) + std::string(" of Item type ") + std::to_string(a + 1) + std::string(". \n")
The problem is here:
"There are " + totals[a] + " of Item type " + (a + 1) + ". \n"
It means char* + int + char* + int + char*. You need to print them out separately or change the int to a std::string.
Use C++-style formatting instead:
std::ostringstream oss;
oss << "There are " << totals[a] << " of Item type " << (a + 1) << ". \n";
printableSolution += oss.str();

Concatenation operator in C++?

I have an application in which I need to combine strings within a variable like so:
int int_arr[4];
int_arr[1] = 123;
int_arr[2] = 456;
int_arr[3] = 789;
int_arr[4] = 10;
std::string _string = "Text " + int_arr[1] + " Text " + int_arr[2] + " Text " + int_arr[3] + " Text " + int_arr[4];
It gives me the compile error
Error C2210: '+' Operator cannot add pointers" on the second string of the expression.
As far as I can tell I am combining string literals and integers, not pointers.
Is there another concatenation operator that I should be using? Or is the expression just completely wrong and should figure out another way to implement this?
BTW I am using Visual Studio 2010
Neither C nor C++ allow concatenation of const char * and int. Even C++'s std::string, doesn't concatenate integers. Use streams instead:
std::stringstream ss;
ss << "Text " << int_arr[1] << " Text " << int_arr[2] << " Text " << int_arr[3] << " Text " << int_arr[4];
std::string _string = ss.str();
You can do this in Java since it uses the toString() method automatically on each part.
If you want to do it the same way in C++, you'll have to explicitly convert those integer to strings in order for this to work.
Something like:
#include <iostream>
#include <sstream>
std::string intToStr (int i) {
std::ostringstream s;
s << i;
return s.str();
}
int main (void) {
int var = 7;
std::string s = "Var is '" + intToStr(var) + "'";
std::cout << s << std::endl;
return 0;
}
Of course, you can just use:
std::ostringstream os;
os << "Var is '" << var << "'";
std::string s = os.str();
which is a lot easier.
A string literal becomes a pointer in this context. Not a std::string. (Well, to be pedantically correct, string literals are character arrays, but the name of an array has an implicit conversion to a pointer. One predefined form of the + operator takes a pointer left-argument and an integral right argument, which is the best match, so the implicit conversion takes place here. No user-defined conversion can ever take precedence over this built-in conversion, according to the C++ overloading rules.).
You should study a good C++ book, we have a list here on SO.
A string literal is an expression returning a pointer const char*.
std::stringstream _string_stream;
_string_stream << "Text " << int_arr[1] << " Text " << int_arr[2] << " Text " << int_arr[3] << " Text " << int_arr[4];
std::string _string = _string_stream.str();

unable to construct a complex structure in c++

I have two base structures like following :
struct stuSectionProperties
{
int Field1; // Row | BoxNo | SplitterNo
int Field2; // Col | Adapter | -
double Latitude;
bool IsEast;
int Band;
int CableNo;
SDP::Global::enuSections::Type Section;
stuSectionProperties()
{
this->Field1 = -1;
this->Field2 = -1;
this->Latitude = -1;
this->Band = -1;
this->Section = SDP::Global::enuSections::None;
this->CableNo = -1;
}
const char* toStr()
{
return ((QString) (QString::number(this->Field1) + " , " + QString::number(this->Field2) + " , " + QString::number(Latitude) + " , " + QString::number(IsEast) + " , " + QString::number(Band) + " , "
+ QString::number((int) Section) + QString::number((int) CableNo))).toStdString().c_str();
}
};
and
struct stuSearchResult
{
stuSectionProperties MyData;
QList<stuSectionProperties> Connections;
stuSearchResult()
{
this->MyData.Field1 = -1;
this->MyData.Field2 = -1;
this->MyData.Latitude = -1;
this->MyData.Band = -1;
this->MyData.Section = SDP::Global::enuSections::None;
this->MyData.CableNo = -1;
stuSectionProperties stuDummy;
stuDummy.Band=-1;
stuDummy.CableNo=-1;
stuDummy.Field1=-1;
stuDummy.Field2=-1;
stuDummy.IsEast=-1;
stuDummy.Latitude=-1;
stuDummy.Section= SDP::Global::enuSections::None;
this->Connections.append(stuDummy);
}
const char * toStr()
{
return ((QString) (QString::number(this->MyData.Field1) + " , " + QString::number(this->MyData.Field2) + " , " + QString::number(this->MyData.Latitude) + " , " + QString::number(this->MyData.IsEast) + " , " + QString::number(this->MyData.Band) + " , "
+ QString::number((int) this->MyData.Section) + QString::number((int) this->MyData.CableNo)) + " , " + QString::number(this->Connections[0].Field1) + " , " + QString::number(this->Connections[0].Field2) ).toStdString().c_str();
}
};
whenever I try to create an instance out of second the structure and then try to call its toStr() member I'll get an erro which is saying that these lines have some issues :
+ QString::number(this->Connections[0].Field1) + " , " + QString::number(this->Connections[0].Field2)
can you please tell me whats my problem exactly?
regards.
the assert error says Connections doesn't have the element you referenced. if you print out Connections.size() how many elements does it say the list contains?
returning string.c_str() could be a potential memory issue, as it's returning a pointer to memory that has been freed.
in c++, custom printing is often done by overloading the stream operator in your class:
friend std::ostream &operator<<(std::ostream &os, const myClass &c)
{
return os << c.some << c.val;
}
...
cout << myObj << endl;
...
strstream ss;
ss << "cool: " << myObj << " " << 55;
string s = ss.str();
you could also just pass a reference to a string object in your toStr function:
makeString(string &s)
{
...
s = qstr.toStdString();
}
string s;
makeString(s);
Yes the code has many issues
Normally people don't write "this->x"; they just write "x"; the "this->" is implicit inside methods
As the other answer pointed out, c_str() points to invalid memory here
However, the Connections list should contain at least one element because the constructor appends it there. I think it would help if the poster would also post the code to allocate the structure. It looks like the constructor doesn't get called OR there is other code that clears the Connections list before toStr() is actually called.