C++ reading char from stack to string results in "Unrecognized enum" - c++

I am new to C++ and there must be something that I am missing. My code is this:
std::stack<char> operators;
std::stringstream stream;
stream.str("5.2 + 3");
while(stream.peek() != -1){
char token = static_cast<char>(stream.get());
//some code checking if the token is valid
operators.push(token);
auto tmp = operators.top(); //there I can still see the char (for example '+')
std::string tmpStr = "" + tmp; //But when put into string, there is "Unrecognized enum"
}
The variable tmpStr is filled with "Unrecognized enum" instead of the contents of tmp.
I couldn't find any solution but I believe it must be something very simple.
Thanks for any help.
Edit:
So if I use tmpStr.push_back(tmp) it works. But then I use it like this:
std::queue<std::string> outQueue;
outQueue.push(" " + operators.top());
//some code
std::string result = "";
while(!outQueue.empty()){
result.append(outQueue.front() + " ");
outQueue.pop();
}
//result then has for example something like "5.2 own enum 3 own enum"
There on the positions that are appended from the operators stack, there is "own enum" and not what was actually saved there.

Stop doing "" + something!
This is C++ and it will not magically make a string object out of a string literal.
If the above code actually compiles, it means that somethign is of some integral type and you are taking a stack pointer (const char*) of the location that "" points to and adding a pointer offset onto that. You are not reading some random data until the next NULL.
If you want to convert something to a string you need to convert it. The standard way to this is though a output stream operator.
enum OP
{
OP_ADD,
OP_SUB,
OP_DIV,
OP_MUL
};
std::ostream& operator << (std::ostream& os, OP op)
{
switch (op)
{
case OP_ADD:
os << "ADD";
break;
case OP_SUB:
os << "SUB";
break;
case OP_DIV:
os << "DIV";
break;
case OP_MUL:
os << "MUL";
break;
default:
throw std::logic_error("Invalid OP");
}
}
This can then be used like so:
OP op = OP_ADD;
std::stringstream buff;
buff << op;
std::string sop = buff.str();
But since the above code it quite stupid, I have a shorthand for the object to string conversion:
template <typename T>
std::string to_string(T value)
{
std::stringstream buff;
buff << value;
return buff.str();
}
This can then be used like so:
OP op = OP_ADD;
std::string sop = to_string(op);

Related

Understanding class object [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am trying to create object that will store inside vector using pointers
I can store object inside vector when I don t use pointers, but when I try to use pointers I can not do that
// created class that combine some attributes for file "datum" = date, "vrijeme" = creation of file etc.
class datoteka{
public:
string datum;
string vrijeme;
string velicina;
string ime;
datoteka();
datoteka(string datum, string vrijeme, string velicina, string ime)
{
this -> datum = datum;
this -> vrijeme = vrijeme;
this -> velicina = velicina;
this -> ime = ime;
}
~datoteka();
};
int main()
{
vector <datoteka> fajlovi;
string linija;
string prva;
int i = 0;
datoteka * pokObjDatoteke;
pokObjDatoteke = new datoteka();
std::ifstream pisi("list.txt"); //file is open
while(getline(pisi,linija)) //get first line of file
{
string vrijednost;
stringstream red; //create stream from line
string datoteka[4]; // create array to store seperate information
red << linija;
while(!red.eof() && i != 4) // since line containt lot of tabs i
read just first for values
{
red >> vrijednost;
datoteka[i]= vrijednost;
i++;
cout << vrijednost << " ovo je vrijednost" << endl;
}
pokObjDatoteke->datum = datoteka[0];
pokObjDatoteke->vrijeme = datoteka[1];
pokObjDatoteke->velicina = datoteka[2];
pokObjDatoteke->ime = datoteka[3];
fajlovi.push_back(*pokObjDatoteke); /**** problem ****
}
return 0;
}
I want to store objects in vector, instead I get just some memory location, probably from pointer but how can I store object and not address
This:
fajlovi.push_back(*pokObjDatoteke);
stores a copy of the object pokObjDatoteke points to in the vector. The pointed-to object is then leaked, since you never delete it.
Do you really need pointers here though? Your vector contains value types, not pointers, so just use emplace_back to construct your objects directly in the vector:
while (getline(pisi, linija))
{
string vrijednost;
stringstream red;
string datoteka[4];
red << linija;
while (!red.eof() && i != 4) {
red >> vrijednost;
datoteka[i]= vrijednost;
i++;
cout << vrijednost << " ovo je vrijednost" << endl;
}
fajlovi.emplace_back(datoteka[0], datoteka[1], datoteka[2],
datoteka[3]);
}
However, if you really want pointers in your vector, then declare it as such:
vector <datoteka*> fajlovi;
and then change the push_back call in your original code to:
fajlovi.push_back(pokObjDatoteke);
This will push the pointers into the vector. You need to remember to delete them when the vector is destroyed, or else all the objects will get leaked:
for (auto* obj : fajlovi) {
delete obj;
}
Manual memory management like this is error-prone and a headache. Don't do it. Use smart pointers instead, like shared_ptr. Remove these lines in your original code:
vector <datoteka> fajlovi;
// ...
datoteka * pokObjDatoteke;
pokObjDatoteke = new datoteka();
and replace them with:
#include <memory>
// ...
vector <shared_ptr<datoteka>> fajlovi;
// ...
auto pokObjDatoteke = make_shared<datoteka>();
and then push_back with:
fajlovi.push_back(pokObjDatoteke);
No need to call new or delete.
However, again, it does not look like you need pointers at all. You can just use value types as shown in the beginning of this answer.
If you want to store objects, then why are you using pointers?
datoteka pokObjDatoteke;
while (...)
{
...
pokObjDatoteke.datum = datoteka[0];
pokObjDatoteke.vrijeme = datoteka[1];
pokObjDatoteke.velicina = datoteka[2];
pokObjDatoteke.ime = datoteka[3];
fajlovi.push_back(pokObjDatoteke);
}
Why are you trying to use pointers when, like you said, not using pointers works?
While the OP didn't disclose an example of the input file, this line (besides all the issues pointed out in the other answers) seems suspicious
while(!red.eof() && i != 4) {...}
See e.g. Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
A better pattern is to perform the extraction and then check if it was successful.
while( some_stream >> some_data ) {...}
OP's code could be rewritten into something like this
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
class datum
{
std::string a_, b_, c_, d_;
public:
datum() = default;
datum(std::string const &a, std::string const &b, std::string const &c, std::string const &d)
: a_(a), b_(b), c_(c), d_(d)
{}
friend std::istream &operator>> (std::istream &is, datum &obj)
{
return is >> obj.a_ >> obj.b_ >> obj.c_ >> obj.d_;
}
friend std::ostream &operator<< (std::ostream &os, datum const &obj)
{
return os << "a: '" << obj.a_ << "', b: '"<< obj.b_
<< "', c: '" << obj.c_ << "', d: '" << obj.d_ << '\'';
}
};
int main()
{
std::vector<datum> data;
std::ifstream in_stream {"list.txt"};
if ( !in_stream )
{
std::cout << "Error: unable to open input file.\n";
return -1;
}
std::string line, junk;
while(getline(in_stream, line))
{
// This won't consider an error to have empty lines in the file
if (line.empty())
continue;
std::istringstream iss(line);
datum dd;
iss >> dd;
// Stops if there are more or less strings than required in the line
if ( !iss or iss >> junk)
break;
data.push_back(std::move(dd));
}
for (auto const & d : data)
std::cout << d << '\n';
}
Testable here.

How do I concatenate "constant strings" and chars?

What is the "proper way" to do the following? (Note, I don't want to output the message to the screen (yet), the data needs to be stored in a variable.)
std::cout << "Enter a letter: ";
char input;
std::cin >> input;
std::string message = "Today's program was brought to you by the letter '" + input + "'.";
The code gives me the error message invalid operands of types const char* and const char [3] to binary operator+.
I understand why this message is occurring. When Googling for a solution, the results that come up recommend casting each item into a string in turn. However, this becomes impractical if you have to concatenate a dozen items:
std::string("x:") + x + std::string(", y:") + y + std::string(", width:") + width + std::string(", height:") + height + ...;
What is the "proper way" in c++ to concatenate strings, chars, char arrays, and any other data that is convertible, into a single string? Is there anything like Python's beautiful string formatting features in c++?
What you are trying to do won't work because C++ views your concatenation as an attempt to add several char pointers. If you explicitly cast the first element in the series to an std::string it should work.
Change your original code
string message = "Today's program was brought to you by the letter '" + input + "'.";
to this:
string message = std::string("Today's program was brought to you by the letter '")
+ input + "'.";
q.v. this SO post which discusses this problem in greater detail (though I don't know why it got closed as not being a real question).
There's several ways to do this, but one way that's a good balance between simplicity of implementation and convenience is to use a "formatter" class which wraps std::stringstream like so:
string message = formatter() << "Today's program was brought to you by the letter '" << input << "'.";
Where formatter can be defined very simply in a header file as follows:
#include <sstream>
class formatter {
public:
template <typename T>
formatter & operator<<(const T & o) {
stream_ << o;
return *this;
}
const std::string str() const { return stream_.str(); }
operator std::string() {
return stream_.str();
}
private:
std::ostringstream stream_;
};
What's going on there: If you try to use a temporary std::stringstream() instead of formatter() above, it doesn't work because
std::stringstream is not implicitly convertible to std::string
You can't even do it like this
std::string message = (std::stringstream() << "foo" << input << "bar").str(); because, std::stringstream returns std::ostream & from its stream operations (rather than std::stringstream &), and you cannot convert an ostream to a string in general.
The formatter class just lets you construct and use a stringstream all in one line with a minimum of boiler plate.

Delete NULLs from std::string

I'm using a third party code which has its own implementation for std::ostream operator<<, to handle the third party's type.
I'm using stringstream for this output - like:
string ToString(const thrdPartyType& structure)
{
stringstream outputStream;
outputStream<<structure;
return outputStream.str();
}
...
string str = ToString(structure);
...
This structure contains pointer members, which are set to NULL. When using the operator<< and the assignment of str() into a string, I see (via gdb - print str) that there are many leading '\000' characters, then the string data I need.
How can I trim those NULLs in order to get only the real, not empty data?
P.S. The exact code works fine in Windows VC++...
Thank you.
Are you looking for a workoround like this?
string ToString(const thrdPartyType& structure)
{
stringstream outputStream;
outputStream << structure;
stringstream workaround;
while(! outputStream.eof ) {
char t;
outputStream >> t;
if(t != '\0')
workaround << t;
}
return workaround .str();
}
If you have boost available, something like the following will replace all instances of null in a string with another value.
boost::replace_all(str,boost::as_array(""),"NULL");
For example
char buf[10] = "hello";
string str(buf,buf+10);
boost::replace_all(str,boost::as_array(""),"NULL");
cout << str << endl;
Produces the following output
helloNULLNULLNULLNULLNULL

How to cast wchar_t into int for displaying the code point?

I have a simple function in my program, when I was wanting to mess around with unicode and do stuff with it. In this function, I wished to display the code value of the character the user entered. It SEEMED possible, here's my function:
wstring listcode(wchar_t arg) {
wstring str = L"";
str += static_cast<int> (arg); //I tried (int) arg as well
str += L": ";
str += (wchar_t) arg;
return str;
}
Now as you see I just wanted to display the integer value (like an ascii character, such as (int) "a"), but something like listcode(L"&") will be displayed as &: & !
Is it not possible to find the integer value of a wide character like that?
In C++, you cannot add anything to strings but characters and other strings. There is no implicit conversion from int (or anything else) to string. That's just the way the string type is designed.
What you do instead is to use string streams:
std::wstring listcode(wchar_t arg)
{
std::wostringstream oss;
oss << static_cast<int>(arg);
oss << L": ";
oss << arg;
return oss.str();
}
In practice, however, when converting to strings in C++, it's better to have functions writing to a stream, than returning a string:
void listcode(std::wostream os, wchar_t arg)
{
os << static_cast<int>(arg);
os << L": ";
os << arg;
}
That way, if you want to output something to the console or to a file, you can directly pass std::cout or a file stream, and if you want a string, you just pass a string stream.

How can I check if a number (double type) stored as a string is a valid double number in C++?

I'm having an issue with a program I'm working on in C++. I am asking the user to input a valid number. I take it in as a string because the particular assignment I'm doing, it makes it easier in the long run. For basic error checking, I want to check to see if the number entered is a valid number. Example:
Enter number: 3.14
This would be valid
Enter number: 3.1456.365.12
This shouldn't be valid
use strtod, which converts a string to a double and returns any characters it couldn't interpret as part of the double.
double strtod(const char* nptr, char** endptr)
Like this:
char* input = "3.1456.365.12";
char* end;
strtod(input, &end);
if (*input == '\0')
{
printf("fail due to empty string\n");
}
if (end == input || *end != '\0')
{
printf("fail - the following characters are not part of a double\n%s\n", end);
}
I think boost::lexical_cast should help you here
An example using only standard C++:
#include <sstream>
// ...
double dbl = 0.0;
std::istringstream num("3.1456.365.12");
num >> dbl;
if(!num.fail() &&
num.eof()) // This second test is important! This makes sure that the entire string was converted to a number
{
// success
}
else
{
// failure
}
Bonus generic template function version:
#include <sstream>
#include <string>
#include <exception>
// Version that throws an exception on a bad parse:
template <typename T>
T parse(const std::string& str)
{
T value;
std::istringstream parser(str);
parser >> value;
if(!parser.fail() && parser.eof())
{
return value;
}
else
{
throw "bad lexical cast";
}
}
// usage:
double foo = parse<double>("3.14234");
// Non-exception, error code version
template <typename T>
bool parse(const std::string& str, T& value)
{
std::istringstream parser(str);
parser >> value;
return (!parser.fail() && parser.eof());
}
// usage:
double foo = 0.0;
bool success = parser<double>("3.11234", foo);
If you have no boost, you always can use strtod
You can use strtoX (where X is f for float, l for long, ul for unsigned long, etc.), choosing for the kind of number you want. One of the parameters you give it is an "end pointer", which points to the first character in the string that could not be converted into the target number type.
In your case, what you're apparently looking for is that the end pointer should be at the end of the string, indicating that all characters in the string were converted to the target type.
Edit: Sorry, didn't notice that you'd mentioned 'double' in the title (but not the question itself). That being the case, you'd use strtod, as a couple of others have also advised.
The best way is to make an actual attempt to convert your string to double using any of the standard and/or idiomatic ways to do the conversion, and check for errors afterwards. In C that would be functions from strto... group (which are, of course, perfectly usable in C++ as well). In C++ you can use stream-based conversion idiom.
One thing to watch for though is that the common convention in standard conversion methods is to convert "as much as possible" and not consider any extra characters as an error. For example, a string "123abc" is normally considered valid input, with only "123" part getting converted. All usable methods provide you with the way to detect the fact that there is something extra after the actual number, if you want to treat this situation as an error. But it is up to you to take the additional steps to perform this verification.
A simple option is to use the sscanf function:
const char * num_as_str = "3.1416";
double num;
if(std::sscanf(num_as_str, "%lg", &num) == 1)
{
std::cout << "You correctly entered the number " << num << "\n";
}
If you want to get fancy you can use istringstream:
std::istringstream iss(num_as_str);
if(iss >> num)
{
std::cout << "You correctly entered the number " << num << "\n";
}
If you want to get extra-fancy you can use boost's lexical_cast:
try
{
num = boost::lexical_cast<double>(num_as_str);
}
catch(boost::bad_lexical_cast &)
{
std::cout << "What you entered is not a proper number" << num << "\n";
}
Ah, I loved these assignments. A good old hand written lexer is the way to go (since you are still in the begining days -- don't try to use boost just yet). They are fast, easy to write and extremely fun to play with. If you can get a copy of Levine's book on Lex/Yacc, look up the first couple of chapters for ideas.
As mentioned by AndreyT, the best way is to attempt to convert the string into a float and check for an error. Personally I would opt to use std::istringstream, as you're using C++. Something like the following should work:
float ff;
std::istringstream istr;
std::string input("1234.5678");
// set the stream to have your string as its base
istr.str(input);
// now try to read the number:
istr >> ff;
if (istr.fail())
{
// some error in the parsing
}
istringstream is part of STL, so you shouldn't need any additional libraries, and it will also with with exceptions if that's your choice. More information can be found here: http://www.cplusplus.com/reference/iostream/istringstream/
You could use regular expressions. Since you already have a string, it would be easy to compare that with this regex:
/^\d+(\.\d+)?$/
The library regex.h can help you here. See this: regex.h
This is my quick hack :)
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template <typename T>
bool fromStr(const std::string& str, T& var)
{
std::stringstream convertor;
convertor << str;
convertor >> var;
if( convertor.fail() )
return false;
char c = static_cast<char>( convertor.get() );
return convertor.eof() || c == '\n' || c == ' ' || c == '\t';
}
int main()
{
double d;
std::string str = "5.04146.55";
if( fromStr<double>(str, d) )
{
std::cout << "Valid conversion!, d = " << d;
}
else
{
std::cout << "Invalid conversion!";
}
}