Say I want to print:
============
Some message
============
And:
=======================
Other Message long one
=======================
The number of "=" changes based on the message length. What is the most efficient way to print this sort of a thing?
No boost, just STL please.
std::string line(msg.length(), '=');
cout << line << "\n" << msg << "\n" << line << endl;
You don't specify how you are measuring "efficiency" in this context. Here's one solution that is efficient in terms of code you must write and number of allocations:
#include <string>
#include <iostream>
using namespace std;
void format(const std::string& msg)
{
std::string banner(msg.length(), '=');
cout << banner << endl
<< msg << endl
<< banner << endl;
}
int main(int argc, char *argv[])
{
format("Some message");
format("Other message long one");
return 0;
}
I can imagine other alternatives that avoid allocating a temporary string for the banners, but those might come at an increased cost of the actual printing.
iomanip variant, just for fun.
const std::string hello("hello world!");
std::cout << std::setfill('=') << std::setw( hello.length() + 1) << "\n"
<< hello << "\n";
<< std::setfill('=') << std::setw( hello.length() + 1 ) << "\n";
Related
I want to know how can i read the standard input just for 5 seconds like you just have 5 seconds to write.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr << ".\n";
cout << "What is your favorite team? ";
getline (cin, mystr);
cout << "I like " << mystr << " too!\n";
return 0;
}
Like that the user have all the time he want to write. Did getline or read have any option to force the getline to stop after 5sec ?
Thank you
A possible solution is to use poll() and write your own getline() function (tested on xubuntu 18.04 with g++ 7.5.0):
Here the implementation of my getline_timeout(int, std::string):
std::string getline_timeout(int ms, std::string def_value)
{
struct pollfd fds;
fds.fd = STDIN_FILENO;
fds.events = POLLIN;
int ret = poll(&fds, 1, ms);
std::string val;
if (ret > 0 && ((fds.revents & POLLIN) != 0)) {
//cout << "has data" << endl;
std::getline(std::cin, val);
} else {
//cout << "timeout / no data" << endl;
val = def_value;
}
return val;
}
#include <iostream>
#include <string>
#include <poll.h>
#include <unistd.h>
std::string getline_timeout(int ms, std::string def_value);
int main(int argc, char *argv[])
{
std::cout << "What's your name ? " << std::flush;
// Ask for the name
std::string mystr = getline_timeout(5000, "John Doe");
std::cout << "Hello " << mystr << std::endl;
std::cout << "What is your favorite team ? " << std::flush;
// Ask for the team
mystr = getline_timeout(5000, "Gryffindor");
std::cout << "I like " << mystr << " too!" << std::endl;
return 0;
}
The API getline() can not do what you want.
There are two way you can try:
- multi thread can work
- single thread with multiplexing IO like select/poll/epoll/iocp
In fact, they work same : setting a timer and wait for I/O input or timeout.
Why can't I use "fixed" and "setprecision()" with the +operator to format it into a string and that I only can use it only with the less-than-less-than-operator to format it for cout. What are other ways I can implement this?
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double a = 157.2734;
cout << "This number is " << fixed << setprecision(1) << a << "." << endl;
string line = "This number is " + fixed + setprecision(1) + a + "." + "\n"; // This doesn't work this way! Why!?!?!?
cout << line;
return 0;
}
Why can't I use "fixed" and "setprecision()" with the +operator to format it into a string?
Have a closer look at std::fixed and std::setprecision().
The complete signature of std::fixed:
std::ios_base& fixed(std::ios_base& str);
So, it is designed to work with streams exclusively.
In the case of std::setprecision(), it's a bit tricky:
/*unspecified*/ setprecision( int n );
However:
Returns an object of unspecified type such that if str is the name of an output stream of type std::basic_ostream or an input stream of type std::basic_istream, then the expression str << setprecision(n) or str >> setprecision(n) behaves as if the following code was executed:
str.precision(n);
So, it might have worked if there were a std::string::precision() method but there isn't one.
What are other ways I can implement this?
The possible solution:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main()
{
double a = 157.2734;
cout << "This number is " << fixed << setprecision(1) << a << "." << endl;
ostringstream fmtStr;
fmtStr << "This number is " << fixed << setprecision(1) << a << ".\n";
string line = fmtStr.str();
cout << line;
return 0;
}
Output:
This number is 157.3.
This number is 157.3.
Life demo on ideone
I am trying to solve the relatively simple problem of being able to write a double to a file and then to read the file into a double again. Based on this answer I decided to use the human readable format.
I have successfully circumvented the problems some compilers have with nan and [-]infinity according to this question. With finite numbers I use the std::stod function to convert the string representation of a number into the number itself. But from time to time the parsing fails with numbers close to zero, such as in the following example:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
stream << small;
std::cout << "serialized: " << stream.str() << std::endl;
double out = std::stod(stream.str());
std::cout << "de-serialized: " << out << std::endl;
return 0;
}
On my machine the result is:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
terminate called after throwing an instance of 'std::out_of_range'
what(): stod
The program has unexpectedly finished.
That is, the number is too close to zero to be properly parsed. At first I thougth that the problem is that this number is denormal, but this doesn't seem to be the case, since the mantissa starts with a 9 and not a 0.
Qt on the other hand has no problems with this number:
#include <cmath>
#include <limits>
#include <QString>
#include <QTextStream>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
QString string = QString::number(small, 'g', maxPrecision);
QTextStream stream(stdout);
stream.setRealNumberPrecision(maxPrecision);
stream << "serialized: " << string << '\n';
bool ok;
double out = string.toDouble(&ok);
stream << "de-serialized: " << out << '\n' << (ok?"ok":"not ok") << '\n';
return 0;
}
Outputs:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
de-serialized: 9.2263152681638151025201733115952403273156653201666065e-318
ok
Summary:
Is this a bug in the gcc implementation of standard library?
Can I circumvent this elegantly?
Should I just use Qt?
Answering question #2:
This is probably my "C-way" kind of thinking, but you could copy the double into a uint64_t (mem-copying, not type-casting), serialize the uint64_t instead, and do the opposite on de-serialization.
Here is an example (without even having to copy from double into uint64_t and vice-versa):
uint64_t* pi = (uint64_t*)&small;
stringstream stream;
stream.precision(maxPrecision);
stream << *pi;
cout << "serialized: " << stream.str() << endl;
uint64_t out = stoull(stream.str());
double* pf = (double*)&out;
cout << "de-serialized: " << *pf << endl;
Please note that in order to avoid breaking strict-aliasing rule, you actually do need to copy it first, because the standard does not impose the allocation of double and uint64_t to the same address-alignment:
uint64_t ismall;
memcpy((void*)&ismall,(void*)&small,sizeof(small));
stringstream stream;
stream.precision(maxPrecision);
stream << ismall;
cout << "serialized: " << stream.str() << endl;
ismall = stoull(stream.str());
double fsmall;
memcpy((void*)&fsmall,(void*)&ismall,sizeof(small));
cout << "de-serialized: " << fsmall << endl;
If you're open to other recording methods you can use frexp:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
int exp;
double x = frexp(small, &exp);
//std::cout << x << " * 2 ^ " << exp << std::endl;
stream << x << " * 2 ^ " << exp;
int outexp;
double outx;
stream.seekg(0);
stream >> outx;
stream.ignore(7); // >> " * 2 ^ "
stream >> outexp;
//std::cout << outx << " * 2 ^ " << outexp << std::endl;
std::cout << small << std::endl << outx * pow(2, outexp) << std::endl;
return 0;
}
For some reason it skips over the first input an goes straight to the second one.
#include<iostream>
#include<string>
using namespace std;
int stringWork()
{
const int LENGTH = 40;
char firstString[LENGTH], secondString[LENGTH];
cout << "Enter First String: ";
//it skips over this following line
cin.getline(firstString, LENGTH);
cout << "Enter Another String: ";
cin.getline(secondString, LENGTH);
if (strcmp(firstString, secondString) == 0)
cout << "You entered Same string two times\n";
else
cout << "The two strings you entered are not the same\n";
system("pause");
return 0;
}
int main()
{
stringWork();
return 0;
}
it only allows input for one string
This piece of code works on my machine just fine. However, please do change #include <string> to #include <string.h> or #include <cstring>, and add #include <stdlib.h> or #include <cstdlib>.
Fix the code like this:
#include <iostream>
#include <string>
void stringWork()
{
const int LENGTH = 40;
char firstString[LENGTH], secondString[LENGTH];
std::cout << "Enter First String: " << std::flush;
std::cin.getline(firstString, LENGTH);
std::cout << "Enter Another String: " << std::flush;
std::cin.getline(secondString, LENGTH);
if (strcmp(firstString, secondString) == 0) {
std::cout << "You entered Same string two times." << std::endl;
} else {
std::cout << "The two strings you entered are not the same." << std::endl;
}
}
int main()
{
stringWork();
return 0;
}
Some notes about my version of your code:
Please don't use using namespace std.
Use std::flush to flush the characters in the output stream. This is necessary because usually the characters are only flushed with std::endl or in some implementations if you add a newline character.
Avoid mixing C and C++ code as you did. Use the std::getline method to read a line directly into a std::string. Shown in the next example.
Please care about your code style, especially if you post it in the public.
A even better implementation would avoid any C code and use just C++:
#include <iostream>
#include <string>
void stringWork()
{
std::cout << "Enter First String: " << std::flush;
std::string firstString;
std::getline(std::cin, firstString);
std::cout << "Enter Another String: " << std::flush;
std::string secondString;
std::getline(std::cin, secondString);
if (firstString == secondString) {
std::cout << "You entered Same string two times." << std::endl;
} else {
std::cout << "The two strings you entered are not the same." << std::endl;
}
}
I've been trying to format the output to the console for the longest time and nothing is really happening. I've been trying to use as much of iomanip as I can and the ofstream& out functions.
void list::displayByName(ostream& out) const
{
node *current_node = headByName;
// I have these outside the loop so I don't write it every time.
out << "Name\t\t" << "\tLocation" << "\tRating " << "Acre" << endl;
out << "----\t\t" << "\t--------" << "\t------ " << "----" << endl;
while (current_node)
{
out << current_node->item.getName() // Equivalent tabs don't work?
<< current_node->item.getLocation()
<< current_node->item.getAcres()
<< current_node->item.getRating()
<< endl;
current_node = current_node->nextByName;
}
// The equivalent tabs do not work because I am writing names,
// each of different length to the console. That explains why they
// are not all evenly spaced apart.
}
Is their anything that I can use to get it all properly aligned with each other?
The functions that I'm calling are self-explanatory and all of different lengths, so that don't align very well with each other.
I've tried just about everything in iomanip.
Think of it like using Microsoft Excel :)
You think of your stream as fields. So you set the width of the field first then you insert your text in that field. For example:
#include <iostream>
#include <iomanip>
#include <string>
int main()
{
using namespace std;
string firstName = "firstName",
secondName = "SecondName",
n = "Just stupid Text";
size_t fieldWidth = n.size(); // length of longest text
cout << setw(fieldWidth) << left << firstName << endl // left padding
<< setw(fieldWidth) << left << secondName << endl
<< setw(fieldWidth) << left << n << endl;
cout << setw(fieldWidth) << right << firstName << endl // right padding
<< setw(fieldWidth) << right << secondName << endl
<< setw(fieldWidth) << right << n << endl;
}
......
......
The field width means nothing but the width of the text + spaces. You could fill anything other than spaces:
string name = "My first name";
cout << setfill('_') << setw(name.size() + 10) << left << name;
.....
output::
My first name__________
......
I think the best way is to figure out your format then, write a new formatter that does all what you want:
#include <iostream>
#include <iomanip>
#include <string>
std::ostream& field(std::ostream& o)
{
// usually the console is 80-character wide.
// divide the line into four fields.
return o << std::setw(20) << std::right;
}
int main()
{
using namespace std;
string firstName = "firstName",
secondName = "SecondName",
n = "Just stupid Text";
size_t fieldWidth = n.size();
cout << field << firstName << endl
<< field << secondName << endl
<< field << n << endl;
}
If you started thinking about parametrized manipulators, only that accept one int or long parameter are easy to implement, other types are really obscure if you are not familiar with streams in C++.
Boost has a format library that allows you to easily format the ourput like the old C printf() but with type safety of C++.
Remember that the old C printf() allowed you to specify a field width. This space fills the field if the output is undersized (note it does not cope with over-sized fields).
#include <iostream>
#include <iomanip>
#include <boost/format.hpp>
struct X
{ // this structure reverse engineered from
// example provided by 'Mikael Jansson' in order to make this a running example
char* name;
double mean;
int sample_count;
};
int main()
{
X stats[] = {{"Plop",5.6,2}};
// nonsense output, just to exemplify
// stdio version
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
stats, stats->name, stats->mean, stats->sample_count);
// iostream
std::cerr << "at " << (void*)stats << "/" << stats->name
<< ": mean value " << std::fixed << std::setprecision(3) << stats->mean
<< " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
<< " samples\n";
// iostream with boost::format
std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
% stats % stats->name % stats->mean % stats->sample_count;
}
Give up on the tabs. You should be able to use io manipulators to set the field width, the fill character, and the format flag (to get left or right justification). Use the same values for the headings as you do for the data, and everything should come out nicely.
Also beware that you've switched Rating and Acres in your example.
You can write a procedure that always print the same number of characters to standard output.
Something like:
string StringPadding(string original, size_t charCount)
{
original.resize(charCount, ' ');
return original;
}
And then use like this in your program:
void list::displayByName(ostream& out) const
{
node *current_node = headByName;
out << StringPadding("Name", 30)
<< StringPadding("Location", 10)
<< StringPadding("Rating", 10)
<< StringPadding("Acre", 10) << endl;
out << StringPadding("----", 30)
<< StringPadding("--------", 10)
<< StringPadding("------", 10)
<< StringPadding("----", 10) << endl;
while ( current_node)
{
out << StringPadding(current_node->item.getName(), 30)
<< StringPadding(current_node->item.getLocation(), 10)
<< StringPadding(current_node->item.getRating(), 10)
<< StringPadding(current_node->item.getAcres(), 10)
<< endl;
current_node = current_node->nextByName;
}
}