This is a simple function which will take value from user and if value is invalid then the function will call itself recursively until a valid input is provided.
#include<iostream>
using namespace std;
void getnum(){
int num;
string strnum;
getline(cin, strnum);
try{
num = stoi(strnum);
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input: abc,abc,abc,4):
4
2494464
2494464
4201200
*/
Using the recursive approach the program is creating a new instance of the function every time an invalid argument is passed. After receiving a valid argument, function is printing multiple values(garbage values) of num due to multiple instances created.
The problem is that I want only the last value(correct one) to be printed. So I tried setting a 'flag' to control the execution of cout<<"\n"<<num.
#include<iostream>
using namespace std;
void getnum(){
int flag = 0;
int num;
string strnum;
getline(cin, strnum);
try{
flag = 1;
num = stoi(strnum);
}
catch(invalid_argument &ia){
flag = 0;
cout<<"Invalid argument\n";
getnum();
}
if(flag)
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input:abc,abc,abc,4)
4 */
It solves my problem but still multiple instances are being created which I think is wastage of memory.
Is there any better way to do this without using a lot of memory(recursion)?
You get multiple outputs because you print outside "the happy path" - move printing inside the try block.
It's even clearer to put the entire "happy path" inside the try:
void getnum(){
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout<<"\n"<<num;
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
}
The idiomatic solution is to loop rather than recurse:
void getnum(){
while (true)
{
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout << "\n" << num;
return;
}
catch (invalid_argument &){
cout<<"Invalid argument\n";
}
}
}
Related
Hi I need help with some code. I need to test a function but I get a compiler error every time I try to compile. here's what I get, error: comparison between distinct pointer types 'void ()()' and 'const char' lacks a cast.
Here is my code.
#include <iostream>
using namespace std;
void getInput();
bool gameGoing = true;
int main()
{
do{
cout << "hello world this is a test.\n";
getInput();
if(getInput == "false")
{
return 0;
}
}while(gameGoing = true);
}
void getInput()
{
string userInput;
cin >> userInput;
}
Should probably be
#include <iostream>
using namespace std;
string getInput();
bool gameGoing = true;
int main()
{
do
{
cout << "hello world this is a test.\n";
if(getInput() == "false")
return 0;
} while(gameGoing == true);
}
string getInput()
{
string userInput;
cin >> userInput;
return userInput;
}
What I changed:
added a return type to the getInput function, so that the result of it doesn't get dismissed
fixed the if comparison to actually compare the result of getInput function againt the "false" value
fixed the while condition to compare the gameGoing with true value rather than overwriting it
Im sorry about posting a super long code, but when I run this code all I see is this-
Heap size: 1638652
Getting int:
Getting int:
Getting int:
Getting int:
Getting int:
Heap size: 1638653
and it keeps going in a loop with the heapsize being incremented by one.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <exception>
#ifndef WX_REPORT_H
#define WX_REPORT_H
#include <string>
#include <sstream>
using std::string;
using std::stringstream;
typedef struct WX_REPORT
{
string unitType;
string stationName;
string time;
string gpsLoc;
int pressure;
int windSpeed;
int temperature;
int humidity;
int windDirection;
string toString()
{
stringstream str;
str << stationName << ": " << time << "\t" << gpsLoc << "\n";
str << pressure << "\n" << windSpeed << "\n" << temperature << "\n";
str << humidity << "\n" << windDirection;
return str.str();
}
}
WXReport;
#endif
/*
* Reports must be in the following format:
* M or I // Metric or imperial units
*/
using namespace std;
vector<WXReport*> heap;
bool compTime(const WXReport* a, const WXReport* b) {
if(a->time < b->time) { // timing
return false;
} else {
return true; // commands to return true
}
}
void heapAdd(WXReport* wx) {
heap.push_back(wx);
push_heap(heap.begin(), heap.end());
}
WXReport* heapPop() { // header popup
pop_heap(heap.begin(), heap.end());
WXReport* rep = heap.back();
heap.pop_back();
return rep;
}
void getInt(istream &input, int &i) {
string temp;
input>>temp;
cout<<"Getting int: "<<temp<<endl;
i = atoi(temp.c_str());
}
void readInFile(string filename) {
ifstream input(filename);
WXReport *report;
while(!input.eof()) {
report = new WXReport();
getline(input, report->unitType);
getline(input, report->stationName);
getline(input, report->time);
getline(input, report->gpsLoc);
getInt(input, report->pressure);
getInt(input, report->windSpeed);
getInt(input, report->temperature);
getInt(input, report->humidity);
getInt(input, report->windDirection);
heapAdd(report);
cout<<"Heap size: "<<heap.size()<<endl;
}
}
int menu() {
cout<<"\n\nPlease select one: "<<endl;
cout<<"1) Read in another file"<<endl;
cout<<"2) Display the fastest wind speed"<<endl;
cout<<"3) Display weather stations by name"<<endl;
cout<<"4) Display all weather reports"<<endl;
cout<<"5) Remove a weather report"<<endl;
cout<<"6) Write weather reports to file"<<endl;
cout<<"0) Exit"<<endl;
int choice;
cin>>choice;
return choice;
}
void printAllReports() {
cout<<"Printing all reports"<<endl;
for(WXReport* rep: heap) {
cout<<rep->toString()<<endl;
}
cout<<"Done printing reports"<<endl;
}
int main(int argc, char* argv[]) {
string filename = "report.txt";
readInFile(filename);
int choice = menu();
while(choice != 0) {
switch(choice) {
case 1:
cout<<"What file would you like to read in?"<<endl;
cin>>filename;
readInFile(filename);
break;
case 2:
cout<<"Has not been implemented"<<endl;
break;
case 3:
cout<<"Has not been implemented"<<endl;
break;
case 4:
printAllReports();
break;
case 5:
cout<<"Has not been implemented"<<endl;
break;
case 6:
cout<<"Has not been implemented"<<endl;
break;
default:
cout<<"Invalid choice, please try again."<<endl;
}
choice = menu();
}
cout<<"Thank you!"<<endl;
return 0;
}
Important part. If you read nothing else, read this: Always check the error codes and return values.
After ifstream input(filename); you have no idea if the file opened. Testing with input.is_open() gets past that.
If the file isn't open, all those calls to getline fail as does eof(). File not open, can't read end of file and can't exit loop. Even if the the file is open, if you don't check the output of getline, how do you know you read a line?
One of the fun parts of streams is if you test the stream, it tells you if it is in a bad state, so you can write code that looks like
if (getline(...) && getline(...) && ...)
So you don't have to make a massive block of if-else-if or a sea of nested ifs. First bad read and you are out.
The problem with if eof() is covered in the comments to the question. The basic is you don't know if you got the end of the file until you start reading. Also, what happen if you hit the end of the file in the middle of a bunch of reads?
So read a line. If it's good, read the next line, etc... until done.
getInt isn't necessary.
int val;
input >> val;
loads an integer into val, if the stream can be parsed into an int. If it can't, input is marked bad and you can check why. Could be unparsable. Could be end of file.
int val;
if (input >> val)
{
//do stuff
}
else
{
//no int here. Do other stuff
}
Just like above, you can chain the instructions and get
if (input >> val >> anotherval >> ...)
I have this code:
#include <iostream>
#include <string>
#include "header8.h"
using namespace std;
int main()
{
Counter test;
string input;
cout << "Enter a string\n";
getline(cin, input);
test.countcharacters();
test.countnumbers();
}
void Counter::countcharacters(){
for(unsigned int i=0; i<input.length(); i++){
if(input.at(i) == 'a'){
alphabet[0]++;
}
}
}
void Counter::countnumbers(){
for(unsigned int i;i<input.length();i++){
if(input.at(i) == '0'){
numbers[i]++;
}
}
}
My error:
When I enter my string, the value always returns 0. Any idea why?
Post your Counter class definition
As one of the comments correctly stated, I can see no way counter sees the same input var.
Edit: then based on your code the fix should be
replace in main
getline(cin, input);
with
getline(cin, test.input);
and remove
string input;
Here is my solution.
int main()
{
string input;
cout << "Enter a string\n";
getline(cin, input);
Counter test(input); // highlight
test.countcharacters();
test.countnumbers();
}
You need to call the constructor of class Counter and transfer 'input' to Counter::input (of course, you need to add a constructor with a string as the parameter). Or you can write a function as below:
void Counter::setInput(string _input)
{
this.input = _input;
}
and call this function before you start counting.
In my code, I want to prevent the user input not integer words. my code is bottom.
#include<iostream>
#include<fstream>
#include<string>
#include<boost/regex.hpp>
#include<iomanip>
using namespace boost;
using namespace std;
int main()
{
int number;
string name,Telephone,email;
ofstream myoutfile("directory.txt");
ifstream myinfile;
bool isvalid=false;
char a[256];
char b[256];
regex reg_email("^\\w+([\\.-]?\\w+)*#\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$");
regex reg_tel("^\\(?(\\d{3})\\)?-?(\\d{3})-(\\d{4})$");
while(number!=3)
{
cout<<"(1)Add a new record"<<endl;
cout<<"(2)Display the entire database"<<endl;
cout<<"(3)Exit"<<endl;
cin>>number;
if(number==1)
{
cout<<"enter your name."<<endl;
cin>>name;
cout<<"enter your email."<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(b,256);
while (regex_match(b,reg_email)==0)
{
cout<<"data wrong!!!!!!"<<endl;
cin.getline(b,256);
}
cout<<"enter your telephone numbers. EX:012-111-1111"<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(a,256);
while(regex_match(a,reg_tel)==0)
{
cout<<"data wrong!";
cin.getline(a,256);
}
myoutfile<<setiosflags(ios::left)<<setw(30)<<name<<setiosflags(ios::left)
<<setw(30)<<b<<setiosflags(ios::left)<<setw(30)<<a<<endl;
}
else if(number==2)
{
myinfile.open("directory.txt",ios::in);
string temp;
cout<<setiosflags(ios::left)<<setw(30)<<"name";
cout<<setiosflags(ios::left)<<setw(30)<<"email";
cout<<setiosflags(ios::left)<<setw(30)<<"telephone"<<endl;
while(!myinfile.eof())
{
getline(myinfile, temp);
cout<<temp<<endl;
}
myinfile.close();
}
else if(number==3)
{
cout<<"BYE!";
}
else if(scanf("%d",&number)!=1)
{
cout<<"Enter number!!!";
break;
}
}
return 0;
}
I have some question in the code.
First,
It will be fine when while loop run the first time,
but when the loop run the second time, I input an non-integer, it will show messy code.
Does anyone know?
Second,
cout<<"enter your telephone numbers. EX:012-111-1111"<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(a,256);
while(regex_match(a,reg_tel)==0)
{
cout<<"data wrong!";
cin.getline(a,256);
}
in above code, even if I type the correct format of the telephone number,
it always show me the "data wrong!" message, but I type it again, the regex_match test will be fine.
above is my question, sincerely thanks!
I want to declare two types of variables in for's init-statement. like the following codes. I know "for (string word, int numb, ; cin>>word>>numb; )" is not working. just trying to let you know what I am trying to do. My goal is to declare two types of variables with the same lifetime and cin them together. Other way of coding is helpful too. thanks in advance.
#include <iostream>
#include <vector>
#include <string>
#include <utility>
using namespace std;
int main ()
{
cout<<"enter a word and a number"<<endl;
for (string word, int numb, ; cin>>word>>numb; )
{
//do some work
}
return 0;
}
ok, I think this is the closest I can get as someone suggested.
#include <iostream>
#include <vector>
#include <string>
#include <utility>
using namespace std;
int main ()
{
vector<pair<string,int> > pvec;
cout<<"enter a word and a number"<<endl;
{
int numb=0;
for (string word; cin>>word>>numb; )
pvec.push_back(make_pair(word,numb));
}
cout<<pvec[3].second<<endl;
return 0;
}
About the nearest you can get is:
int main ()
{
cout<<"enter a word and a number"<<endl;
{
string word;
for (int numb; cin>>word>>numb; )
{
//do some work
}
}
return 0;
}
The extra set of braces limits the scope of word similarly to the way the loop limits the scope of numb. Clearly, you could reverse the declarations; it might be better (more symmetric) to use:
int main ()
{
cout<<"enter a word and a number"<<endl;
{
string word;
int numb;
while (cin>>word>>numb)
{
//do some work
}
}
return 0;
}
Since there is no increment or initialize operation, the code is really a while loop with a couple of declared variables; this achieves the same result and works.
This is not possible. You can declare two variables of the same basic type in the initialization statement in the for loop, but you cannot declare two variables of different basic types. You have to declare one outside of the for loop.
I'm fairly certain it's not possible to declare 2 variables of 2 different types in a for statement, but I also fail to see the advantage to doing so over something like this:
int main ()
{
cout<<"enter a word and a number"<<endl;
while( cin.good() )
{
string word;
int num;
cin >> word >> num;
//do some work
}
return 0;
}
In general I prefer to use for loops where there is something to count or at least iterate over. Other situations should be using a while or do loop.
The way you are trying to do it is not the cleanest way. I'd do it like this:
string word;
int num;
while(true)
{
cin >> word >> num;
if (!cin.good()) break;
// do some work
}
word and num are in the same scope (same "lifetime")
Note that you'd want to substitute the while(true) with some suitable condition.
If you want word and num to be inside the scope of the loop do something like:
while(true)
{
string word;
int num;
cin >> word >> num;
if (!cin.good()) break;
// do some work
}
OR
{
string word;
int num;
while(true)
{
cin >> word >> num;
if (!cin.good()) break;
// do some work
}
}
I don't know why this would be necessary though.
The following is untested, but should work:
int main()
{
std::cout << "enter a word and a number" << endl;
for (struct { std::string word, int number } vars;
std::cin >> vars.word >> vars.number;
)
{
//do some work
}
return 0;
}
Since c++17:
#include <iostream>
#include <tuple>
int main() {
for (auto && [w,i] = std::tuple{std::string{},int{}} ; std::cin >> w >> i ; )
std::cout << "word " << w << " number " << i << "\n";
return 0;
}