Returning char * instead of string - c++

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.

Related

How to concatenate strings using + operator

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";
}

'+' 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();

Try catch trouble in netbeans

I'm trying to create a search engine that gets information from my SQL database. Right now I'm struggling to make the combobox and textfield work. So far I can only make the first part of the code work, it allows the user to search for a name in the database. The rest however doesn't work at all, resulting in just an empty window where the info should pop up.
Here are some translations of the Swedish words present in the code:
Namn - Name
sokt - Searched
ANSTALLD - Employee
Aid - Employee id
telefon - phone
try
{
if(jComboBoxSokAID.getSelectedItem().equals("Namn"))
{
String namn = jTextFieldSokText.getText();
String namnQuery = "select * from ANSTALLD where namn = '" + namn + "'";
try
{
HashMap <String, String> soktNamn = idb.fetchRow(namnQuery);
jTextAreaSpecialistInfo.setText("Namn: " + soktNamn.get("namn") + "\n" + "Aid: " + soktNamn.get ("aid") + "\n" + "Telefon: " + soktNamn.get ("telefon") + "\n" + "Mail: " + soktNamn.get ("mail"));
if(jComboBoxSokAID.getSelectedItem().equals("Mail"))
{
String mail = jTextFieldSokText.getText();
String mailQuery = "select * from ANSTALLD where mail = '" + mail + "'";
try
{
HashMap <String, String> soktMail = idb.fetchRow(mailQuery);
jTextAreaSpecialistInfo.setText("Namn: " + soktMail.get("namn") + "\n" + "Aid: " + soktMail.get ("aid") + "\n" + "Telefon: " + soktMail.get ("telefon") + "\n" + "Mail: " + soktMail.get ("mail"));
if(jComboBoxSokAID.getSelectedItem().equals("Telefon"))
{
String telefon = jTextFieldSokText.getText();
String telefonQuery = "select * from ANSTALLD where telefon = '" + telefon + "'";
try
{
HashMap <String, String> soktTelefon = idb.fetchRow(telefonQuery);
jTextAreaSpecialistInfo.setText("Namn: " + soktTelefon.get("namn") + "\n" + "Aid: " + soktTelefon.get ("aid") + "\n" + "Telefon: " + soktTelefon.get ("telefon") + "\n" + "Mail: " + soktTelefon.get ("mail"));
if(jComboBoxSokAID.getSelectedItem().equals("AID"))
{
String AID = jTextFieldSokText.getText();
String AIDQuery = "select * from ANSTALLD where aid = '" + AID + "'";
try
{
HashMap <String, String> soktAID = idb.fetchRow(AIDQuery);
jTextAreaSpecialistInfo.setText("Namn: " + soktAID.get("namn") + "\n" + "Aid: " + soktAID.get ("aid") + "\n" + "Telefon: " + soktAID.get ("telefon") + "\n" + "Mail: " + soktAID.get ("mail"));
}
catch (InformatikException e)
{
if(jComboBoxSokAID == null)
jTextAreaSpecialistInfo.setText("Sökningen gav inga resultat");
}
}
}
catch (InformatikException e)
{
}
}
}
catch (InformatikException e)
{
}
}
}
catch (InformatikException e)
{
}
Don't write code this way.
Never have empty catch blocks.
I prefer to have a single try/catch in a method. Nesting them this way is an indication that you ought to refactor a method that's doing too much.
You've mingled persistence and UI code together in the worst way possible. Tease them apart so you can test and use them separately.
You don't close any database resources. This will come to grief.

Heap corruption using strcat

One of my weaknesses is effectively using chars in C++ which is what I am trying to do right now. I have a player class in my game and within the player class, I create a playerCard object which displays various information. This works fine for a single instance of the player object (i.e. Player player) but when I attempt to push_back a player object in to a vector it all goes wrong.
Basically, the program continues to run but the player doesn't render to the screen. When I quit the program, I then get a breakpoint error when main tries to return MSG. The comment about the breakpoint reads:
/*
* If this ASSERT fails, a bad pointer has been passed in. It may be
* totally bogus, or it may have been allocated from another heap.
* The pointer MUST come from the 'local' heap.
*/
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
I have located the error to here
strcat(nameCard, nameChar);
strcat(nameCard, genderChar);
strcat(nameCard, ageChar);
strcat(nameCard, cashHeldChar);
strcat(nameCard, productWantedChar);
within the playerCard class because when I comment this out, I do not get the error. Here is the full playerCard class (Again, it is messy and probably the wrong way for going about things but I am trying to get my head round using chars/strings etc)
#include "Headers.h";
class Playercard{
private:
RECT textbox;
LPD3DXFONT font;
std::string nameStr;
std::string genderStr;
std::string ageStr;
std::string cashHeldStr;
std::string prodWantedStr;
char nameCard[1000];
public:
Playercard()
{
}
void load(char* name, bool male, int age, double cash, char* prod)
{
if(male)
{
genderStr = "Gender: Male\n";
}
else
{
genderStr = "Gender: Female\n";
}
nameStr = "Name: " + static_cast<std::ostringstream*>( &(std::ostringstream() << name))->str() + "\n";
ageStr = "Age: " + static_cast<std::ostringstream*>( &(std::ostringstream() << age))->str() + "\n";
cashHeldStr = "Cash Held: " + static_cast<std::ostringstream*>( &(std::ostringstream() << cash))->str() + "\n";
prodWantedStr = "Product Wanted: " + static_cast<std::ostringstream*>( &(std::ostringstream() << prod))->str() + "\n";
char * nameChar = new char [nameStr.length()+1];
char * genderChar = new char [genderStr.length()+1];
char * ageChar = new char [ageStr.length()+1];
char * cashHeldChar = new char [cashHeldStr.length()+1];
char * productWantedChar = new char [prodWantedStr.length()+1];
strcpy(nameChar, nameStr.c_str());
strcpy(genderChar, genderStr.c_str());
strcpy(ageChar, ageStr.c_str());
strcpy(cashHeldChar, cashHeldStr.c_str());
strcpy(productWantedChar, prodWantedStr.c_str());
strcat(nameCard, nameChar);
strcat(nameCard, genderChar);
strcat(nameCard, ageChar);
strcat(nameCard, cashHeldChar);
strcat(nameCard, productWantedChar);
diagFile.open("Diag.txt");
diagFile.write("Test", 100);
diagFile.close();
}
void setUp(int L, int T, int R, int B)
{
SetRect(&textbox, L,T,R,B);
}
void draw()
{
font->DrawTextA(d3dSprite, nameCard, -1, &textbox, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));
}
LPCSTR plCard()
{
return nameCard;
}
};
Any help would be greatly appreciated. Thank you.
Your nameCard is uninitialized. Replace the first strcat with strcpy, or initialize it with a zero string.
Now, how about using std::string exclusively?
Your main problem is that nameCard is uninitialized. strcat requires a null-terminated string to do its magic, and there's no guarantee that the first, or any, character in nameCard is a null.
However, C strings are unnecessary. Just use std::string all the time. After changing nameCard to a string, I'd change load to (file writing excluded):
void load(const std::string &name, bool male, int age, double cash, const std::string &prod)
{
nameStr = "Name: " + name + "\n";
genderStr = "Gender: " + (male ? "Male" : "Female") + "\n";
ageStr = "Age: " + std::to_string(age) + "\n";
cashHeldStr = "Cash Held: " + std::to_string(cash) + "\n";
prodWantedStr = "Product Wanted: " + prod + "\n";
nameCard = nameStr + genderStr + ageStr + cashHeldStr + prodWantedStr;
}
I would actually just make nameCard a data member, removing the others, and use this:
nameCard.clear();
nameCard += "Name: " + name + "\n";
//add on other parts
Other than that, make plCard() return a std::string and in draw(), use nameCard.c_str(). I hope that clears up what you can do with strings a bit more.
Do note, however, that std::to_string is C++11. C++03 has two common solutions:
std::string str = boost::lexical_cast<std::string>(someNumber);
Or
std::ostringstream oss;
oss << someNumber;
std::string str = oss.str();
I find the three-liner much more readable than a one-liner or two-liner.

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.