Reputation: 3
I've been stuck on this homework assignment all week. Just when I get the program to finally run, I realize that by using just cin >> breed
, if my input has a space it ruins the code (as my program requires gathering 3 separate variables, first an int, then a string, and last a bool). Because this is the second variable, it messes up my code using phrases that have a white character. When I try changing it to cin.get
or cin.getline
, this is the error message I get:
c2664 error "cannot convert argument 1 from std::string to _Elem *"
Below is the code in question (the middle line is giving the error). Any help would be greatly appreciated!
#include <iostream>
#include <string>
using namespace std;
int main()
{
int birthyear;
string breed;
bool vaccines;
cout << "Please enter value for dog's birth year: ";
cin >> birthyear;
cout << "What is the breed of the dog: ";
cin.getline(breed, 100);
cin.ignore();
cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
cin >> vaccines;
}
Upvotes: 0
Views: 2767
Reputation: 882336
First up, you need to be aware that there are two getline
things in C++, one in the I/O area and one in the top-level standard namespace.
cin.getline(breed, 100)
is the one in the I/O area (specifically istream::getline()
and it knows nothing about strings, preferring to work on character arrays. You should probably avoid that one.
The one that does know about strings is std::getline()
and that's generally the preferred one if you don't want to go back to the bad old days of C-legacy "strings".
In addition, you need to be careful in C++ when you mix the type-specific input (like <<
) and line-specific input (like getline
) operations. It's important to know where the file pointer is before and after each operation.
For example, cin << someInt
will leave the file pointer immediately after the integer it reads in. That means, if your next operation is getline()
, it's likely to find everything on the line after that integer (at the bare minimum, this will be the newline character that you entered to get the integer processed), not the next line where you're going to be typing in your string.
A simple fix for your case is to ignore everything up to and including the newline before you attempt to get the next line. That can be done with ignore()
:
#include <iostream>
#include <string>
#include <limits>
using namespace std;
int main() {
int birthyear; string breed; bool vaccines;
cout << "Please enter value for dog's birth year: ";
cin >> birthyear;
cout << "What is the breed of the dog: ";
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
getline(cin, breed);
cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
cin >> vaccines;
// Output what you got.
cout << birthyear << " '" << breed << "' " << vaccines << '\n';
}
You could also opt for ensuring all input is line-based (converting those lines to the correct type once they're entered) since that's likely to ease your task of ensuring the pointers are in the right place, and that errors in input (like entering xyzzy
for an integer) can be better handled.
Something like this should be a good start:
#include <iostream>
#include <string>
#include <limits>
#include <set>
#include <cstdlib>
using namespace std;
// Get string, always valid. Optionally strip leading and
// trailing white-space.
bool getResp(const string &prompt, string &val, bool strip = false) {
cout << prompt;
getline(cin, val);
if (strip) {
val.erase(0, val.find_first_not_of(" \t"));
val.erase(val.find_last_not_of(" \t") + 1);
}
return true;
}
// Get unsigned, must ONLY have digits (other than
// leading or trailing space).
bool getResp(const string &prompt, unsigned long &val) {
string str;
if (! getResp(prompt, str, true)) return false;
for (const char &ch: str)
if (! isdigit(ch)) return false;
val = strtoul(str.c_str(), nullptr, 10);
return true;
}
// Get truth value (ignoring leading/trailing space),
// and allow multiple languages.
bool getResp(const string &prompt, bool &val) {
string str;
if (! getResp(prompt, str, true)) return false;
const set<string> yes = {"yes", "y", "1", "si"};
const set<string> no = {"no", "n", "0", "nyet"};
if (yes.find(str) != yes.end()) {
val = true;
return true;
}
if (no.find(str) != no.end()) {
val = false;
return true;
}
return false;
}
// Test driver for your situation.
int main() {
unsigned long birthYear;
std::string dogBreed;
bool isVaccinated;
if (! getResp("What year was the dog born? ", birthYear)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
if (! getResp("What is the breed of the dog? ", dogBreed, true)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
if (! getResp("Has the dog been vaccinated? ", isVaccinated)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
std::cout
<< birthYear
<< " '" << dogBreed << "' "
<< (isVaccinated ? "yes" : "no") << '\n';
}
Upvotes: 1