C++ cin problems. not capturing input from user - c++

I have the following method which is not capturing anything from the user.If I input New Band for the artist name, it only captures "New" and it lefts out "Band". If I use cin.getline() instead nothing is captured. Any ideas how to fix this?
char* artist = new char [256];
char * getArtist()
{
cout << "Enter Artist of CD: " << endl;
cin >> artist;
cin.ignore(1000, '\n');
cout << "artist is " << artist << endl;
return artist;
}
This worked just fine. Thank you Roger
std::string getArtist()
{
cout << "Enter Artist of CD: " << endl;
while(true){
if ( getline(cin, artist)){
}
cout << "artist is " << artist << '\n';
}
return artist;
}

std::string getArtist() {
using namespace std;
while (true) {
cout << "Enter Artist of CD: " << endl;
string artist;
if (getline(cin, artist)) { // <-- pay attention to this line
if (artist.empty()) { // if desired
cout << "try again\n";
continue;
}
cout << "artist is " << artist << '\n';
return artist;
}
else if (cin.eof()) { // failed due to eof
// notice this is checked only *after* the
// stream is (in the above if condition)
// handle error, probably throw exception
throw runtime_error("unexpected input error");
}
}
}
The whole thing is a general improvement, but the use of getline is possibly the most significant for your question.
void example_use() {
std::string artist = getArtist();
//...
// it's really that simple: no allocations to worry about, etc.
}

This is the specified behaviour; istreams only read up to a space or a newline. If you want an entire line, you use the getline method, as you already discovered.
Also, please use std::string instead of char* in any new C++ code, unless there are very good reasons otherwise. In this case, it will save you from all kinds of problems like buffer overflows, without any extra effort on your part.

If you're going to have white space separators in your input, you need to use getline for your input. That would make your ignore unnecessary.

Related

I'm working on reading and writing to files with c++

Hi guys I'm working on my last assignment of the computer science class. I think I'm doing everything fine but something is wrong. Can you take a look at it and tell what I'm doing wronger here.
here is what I get when I try to submit online on zybooks site:
"Your program produced no output"
Expected:
Ryan Hermle
22.99
Lochness Monster
3.50
Wonder Woman
123456.78
here are instructions from professor:
Constructor:
Takes a string parameter and stores that as fileName. Does not need to do anything else.
append:
Takes a record as a parameter that contains a string and a double
Open an output file stream in append mode using fileName
set its precision to 2 and fixed
Output the name, newline, the money, newline
searchName:
Open an input file stream with fileName
Loop while a getline and a double extraction are successful
if the string parameter is equal to the name read from the getline, then return the double
If the loop finishes without finding anything, return -1 to indicate that name was not found.
getData:
Open an input file stream with fileName
Construct an ostringstream
Set its precision to 2 and fixed
Loop while a getline and a double extraction are successful
ignore the \n left by the >> extraction
write the string, newline, double, newline to the ostringstream
return the string contained by the ostringstream
here is my main:
#include "Database.h"
int main()
{
Database db("data.txt");
db.append(Record{"Ryan Hermle", 22.99});
db.append(Record{"Lochness Monster", 3.50});
db.append(Record{"Wonder Woman", 123456.78});
}
and here is my Database.cpp file:
#include "Database.h"
Database::Database(string file)
{
fileName = file;
}
void Database::append(Record data)
{
ofstream out;
out.open(fileName, ios::app);
out << setprecision(2) << fixed;
cout << data.name << endl;
cout << data.money << endl;
out.close();
}
double Database::searchName(string n)
{
Record s;
ifstream in;
in.open(fileName);
while (getline(in, n) >> s.money)
{
in.ignore();
if (n == s.name)
{
return s.money;
}
}
return -1;
}
string Database::getData()
{
Record s;
ifstream ifs;
ifs.open(fileName);
ostringstream oss;
oss << setprecision(2) << fixed;
while(getline(ifs, s.name) >> s.money)
{
ifs.ignore();
oss << s.name << endl << s.money << endl;
cout << oss.str();
}
return oss.str();
}
Thanks for everyone who replied to my post. I was able figure out the error in my program.
The error was in append Function:
cout << data.name << endl;
cout << data.money << endl;
It should be like this:
out << data.name << endl;
out << data.money << endl;

C++ User defined string needs to contain spaces (but not allowed by program..?)

I'm working on homework for my c++ class, and it's been quite awhile since I've used it. I was wondering if there was a way to allow spaces in a string (instead of it nulling out and ending the string)
my current code is this:
int chapter10() {
string strinput;
char charstr[1000];
int numwords=1;
cout << "Enter a phrase ";
cin >> strinput;
cout << strinput;
const int size = strinput.size() + 1;
strcpy_s(charstr, strinput.c_str());
cout << strinput << endl;
for (int i = 0; i != size; i++) {
if (*(charstr + i) == ' ')
numwords++;
}
cout << "There are " << numwords << " words in that string." << endl;
return 0;
}
The problem I'm having, is for instance, if I type "Hello World" and press enter, it pops the next line (right after the cin) and says "Hello", and the space made it cut the rest of the phrase off.
How does one fix this issue? I don't want to use the str:: things as I barely know what they are, and have really never had to use them, and that would look a bit suspicious to the teacher :P
Update: If you've suggested using getline(cin, strinput); It doesn't work too well. I can from what I see, only type in the 10 to reach my function, but after I press enter, it thinks that I've presses something else, which makes it completely skip the cin to get the string value. But, there is something weird with this, if I type "10 hello world" it does everything correctly. Well, with the exception that it needs to be in the same line as the number to reach the function.
Solved: The use of getline(cin, strinput) works perfectly fine, if you're not using user input before hand. If you are, you're going to need a cin.ignore before the getline(). As stated in the comment by my best answer.
#include <iostream>
#include <iomanip>
#include <string>
#include <limits>
using namespace std;
//~~~Initialize all functions
int chapter10();
//~~~Initializing complete
int main() {
srand(time(0)); //makes rng thingy work instead of choose same numbers cause it doesn't do it on its own. lol
cout << "Enter the chapter number you need to look at: ";
int chapterNumber;
cin >> chapterNumber;
switch (chapterNumber) {
case 1: testingStuff(); break;
case 9: chapter9(); break;
case 10: chapter10(); break;
default: cout << "You chose an invalid chapter number, reload the program."; break;
}
system("pause");//So console doesn't close instantly cause that's not annoying at all...
}
int chapter10() {
string strinput;
char charstr[10000];
int numwords=1;
cout << "Enter a phrase." << endl;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
getline(cin, strinput);
const int size = strinput.size() + 1;
strcpy_s(charstr, strinput.c_str());
for (int i = 0; i != size; i++) {
if (*(charstr + i) == ' ' & *(charstr + (i+1)) != ' ' )//the & is fail safe so multiple space no ++numwords
numwords++;
}
cout << "There are " << numwords << " words in that string." << endl;
return 0;
}
The way I have my code written was I used a switch/case to reach my function. This required user input, which in turn caused my program to 'think' I was still typing for the second input required in the chapter10 function.
Adding in the line of code: cin.ignore(numeric_limits<streamsize>::max(), '\n'); allowed me to cancel the input, and start a new one.
If you want to get all characters an end-user enters on a single line, use getline: instead of cin >> strinput write this:
getline(cin, strinput);
The fact that it is actually std::getline(std::cin, strinput) makes no difference, because your code uses std namespace anyway. In case you were wondering what std:: prefix is, it's a namespace of the Standard C++ library.
You can use getline() function
It copies into a string till a newline is reached or delimiter is found - so it will accept all the spaces till newline is reached
http://www.cplusplus.com/reference/string/string/getline/
or you can also use cin.getline() as shown here -
std::cin input with spaces?
use:
cin >> noskipws >> strinput;
Use std::getline() function. Example:
#include <iostream>
#include <vector>
#include <sstream>
void WordCounter(
const std::vector<std::string> & lines) {
for (int i = 0; i < lines.size(); ++i) {
std::istringstream iss(lines[i]);
std::string word;
int count = 0;
while (iss >> word) {
++count;
}
std::cout << "Line #" << i << " contains " << count << " words." <<
std::endl;
}
}
int main() {
std::string line;
std::vector<std::string> lines;
while (std::getline(std::cin, line)) {
lines.push_back(line);
}
WordCounter(lines);
return 0;
}

Using getline to read from file to a 2d string array

I am trying to read the contents of a text file into a 2D string array, but no matter what I have tried or searched, I can not find a solution. The code is supposed to load a text file separate it into elements by finding horizontal tabs and display the output. When I run the code as is, I receive an error that I found out from searching online, means that I'm trying to manipulate memory I shouldn't be. I'm not asking for the code to be written, just a push in the right direction. Thank you in advance.
this is what I get when I run the program:
0x23fd5c
Process returned -1073741819 (0xC0000005) execution time : 2.344 s
Press any key to continue.
EDIT:: I have corrected the code so it now functions as it should, but it is not storing the last entry of each line in the text file correctly. I can somehow display the number 100 which is the last entry, but when I try to pass that location or display just playList[0][5] , it says it is equal to the first entry of the next line. Any help would be amazing I posted the current code below.
here is my code:
#include <iostream>
#include <string>
#include <iomanip>
#include <cstdlib>
using namespace std;
void readTextFile( int &Count, string playList[50][5]);
void userAddition( int &Count, string playList[50][5]);
int main()
{
string decision;
string playList[50][5];
int Count = 0;
readTextFile(Count, playList);
cout << "If you would like to add to the list, Please enter 'Y'. If you would like to exit
please enter 'N'. ----> ";
getline(cin, decision);
if (decision=="y" || decision=="Y")
userAddition(Count, playList);
else
{
return(0);
}
return 0;
} // End of Main FN.
void readTextFile( int &Count, string playList[50][5])
{
string inputfield;
ifstream infile("c:\\cTunes.txt", ifstream::in);
if ( infile.is_open() )
{
// File is read.
} // end if
else
{
cout << "Error Opening file" << endl;
return; //Program Closes.
} // end else
cout << setw(30)<<left<< "TITLE"<< setw(10) <<left<<"LENGTH"<<
// Outputs a title to each column that is displayed.
setw(40)<< left<<"ARTIST"<< setw(40) << left<<"ALBUM"<<
setw(15) << left <<"GENRE" << setw(5) << left << "RATING" << endl;
getline(infile, inputfield, '\t'); // read until tab
while(! infile.eof()) // loop until file is no longer valid.
{
playList[Count][0] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][1] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][2] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][3] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][4] = inputfield;
getline(infile, inputfield); // read until end of line.
playList[Count][5] = inputfield;
cout << setw(30)<<left<< playList[Count][0] << setw(10) <<left<<playList[Count][1] <<
// Output the line number equal to count.
setw(40)<< left<<playList[Count][2] << setw(40) << left<< playList[Count][3] <<
setw(15) << left << playList[Count][4] << setw(5) << left << playList[Count][5] <<
endl;
/*cout <<"Title: " << setw(25)<<left<< playList[Count][0]<<endl;
cout <<"Length: " << setw(5) <<left<<playList[Count][1] << endl;
cout <<"Artist: " << setw(50)<< left<<playList[Count][2] << endl;
cout <<"Album: " << setw(40) << left<< playList[Count][3] << endl;
cout <<"Genre: " << setw(15) << left << playList[Count][4] << endl;
cout <<"Rating: " << setw(5) << left << playList[Count][5] << endl<<endl;*/
Count++; // Increment counter by 1
getline(infile, inputfield, '\t'); // read next line until tab.
} // end while
infile.close(); // close the file being read from.
cout<<endl<<endl<<playList[0][5]<<endl;
} // End of readTextFile
I believe getline is causing the problem when reading till the end of the line but I'm truly at a loss.
First, note that in the following line:
cout << playList << endl;
you are printing the address of the array, not the contents. you will need
a loop to print the contents.
Second, in the following code:
if ( infile.is_open() )
{
// ok, read in the file
} // end if
else
{
cout << "Error Opening file" << endl;
//a return statement is missing
}
you need a return statement to avoid reading from a closed stream (which can cause a crash)
Finally, your function does not return anything, so it should either be declared void
or return some value (in which there is no sense according to the context).
Hope that helps and good luck!
The readTextFile function does not return anything. You need to return a string. If you are getting the error what(): basic_string::_S_construct null not valid then this is your problem. You can avoid similar problems by using -Wall compiler option.
You are using std::string for storing the string, std::ifstream for reading from a file, std::getline for reading words... you should really use std::vectors instead of arrays:
typedef std::vector<std::string> Line;
std::vector<Line> playList;
It will make things easier for you.
I also recommend you to change the way you read from a file to:
while(getline(...))
{
...
}
But since you are not allowed to use std::vector, your function could look like this:
// reads the content of input file and stores it into playList:
void readTextFile(std::ifstream& infile, std::string playList[][5])
{
std::string line;
for (int lineIndex = 0; getline(infile, line); ++lineIndex)
{
// skip empty lines:
if (line.empty()) continue;
std::string word;
std::istringstream lineStream(line);
for (int wordIndex = 0; getline(lineStream, word, '\t'); ++wordIndex)
{
// skip empty words:
if (line.empty()) continue;
playList[lineIndex][wordIndex] = word;
}
}
}
that could be used like this:
std::string playList[19][5];
std::ifstream infile("c:\\Test.txt");
if (infile.is_open())
{
readTextFile(infile, playList);
infile.close();
}
else
std::cout << "Error Opening file" << std::endl;
Also note that cout << playList << endl; outputs the address of the first word. To print all words, you will have to write a loop.

Output comes out wrong

I am teaching myself C/C++ at the moment, and I got the exercise (from the book I am reading) to write a program that could make an output like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
Using Structures. But my output comes out like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: ,
Here is the code. It's fairly short and simple so it shouldn't be hard to read :)
#include <iostream>
#include <cstring>
using namespace std;
struct Person {
char* firstName;
char* lastName;
};
char* getName(void);
int main() {
Person* ps = new Person;
cout << "Enter your first name: ";
char* name;
name = getName();
ps->firstName = name;
cout << "Enter your last name: ";
char* lastname;
lastname = getName();
ps->lastName = lastname;
cout << "Here's the information in a single string: "
<< ps->lastName << ", " << ps->firstName;
delete ps;
delete name;
delete lastname;
return 0;
}
char* getName() {
char temp[100];
cin >> temp;
cin.getline(temp, 100);
char* pn = new char[strlen(temp) + 1];
strcpy(pn, temp);
return pn;
}
First, there's no such thing as C/C++. You're mixing them, which is wrong. Since you're using C++ headers/new/using, I'll assume you want C++, so here's how you fix your code:
replace all char* and char[] with std::string
get rid of dynamic allocation
So, some changes would be:
struct Person {
std::string firstName;
std::string lastName;
};
or
Person ps;
You are using:
cin >> temp;
cin.getline(temp, 100);
You probably overwrite what you already have with empty string at the end of a line.
Use just one of them.
If you'll stick with using cin >> you may consider setting width() to prevent buffer overflow.
First, the immediate problem is that you read twice from std::cin: first with operator>>, and then with getline. Pick one or the other.
But let's simplify your code a bit. There are simply too many sources of error. Pointers are tricky because they might point to the wrong thing, or you might forget to delete objects, or delete them twice. C-style char arrays as strings are bad because, well, they're not strings, and they don't behave like strings.
So let's use the standard library's string class:
#include <iostream>
#include <string>
struct Person {
std::string firstName;
std::string lastName;
};
std::string getName(void);
int main() {
Person ps;
cout << "Enter your first name: ";
std::string name = getName();
ps.firstName = name;
cout << "Enter your last name: ";
std::string lastname = getName();
ps.lastName = lastname;
cout << "Here's the information in a single string: "
<< ps.lastName << ", " << ps.firstName;
}
std::string getName() {
std::string temp;
std::getline(cin, temp);
return temp;
}
This is a fairly simple, almost mechanical substitution, basically just replacing char* by std::string, and removing the bits that are no longer necessary.
Of course, as pointed out in a comment, I've omitted all forms of error checking, which a real program should definitely do.
No no no, wayyyy too complicated. Use real C++ idioms. The program could be as simple as this:
#include <string>
#include <iostream>
int main()
{
std::string firstName, lastName;
if (!(std::cout << "Your first name: " &&
std::getline(std::cin, firstName) &&
std::cout << "Your last name: " &&
std::getline(std::cin, lastName) ))
{
std::cerr << "Error: unexpected end of input!\n";
return 0;
}
std::cout << "You are " << firstName << " " << lastName << ".\n";
}
As a variation on the theme, you could put each getline in a loop until the user inputs a non-empty line:
std::cout >> "Your first name: ";
for ( ; ; )
{
if (!(std::getline(std::cin, firstName))
{
std::cerr << "Error: unexpected end of input.\n";
return 0;
}
if (!firstName.empty())
{
break;
}
std::cout << "Sorry, please repeat - your first name: ";
}

Validate the length of a char * taken from std::cin

I have a pointer called char * panimal_name. This pointer should only be able to take in 20 characters and if the user enters more, it must ask the user to re-enter.
I've tried counting the characters in the stream and also using strlen(), however I'm still having problems.
cout << "Enter Animal Name: ";
cin.ignore();
cin.getline(panimal_name, 20);
Any help would be appreciated.
EDIT: Well I only want it to take at most 20 characters from the user. If that 20 is exceeded it should then ask the user to re-enter valid input. However in this setup, it now messes up the stream for my next inputs. The reason I'm using this, rather than a std::string, is that I'm learning pointers at the moment.
P.S. I know a string would probably be better in this situation for ease of use.
According to MSDN:
If the function extracts no elements or _Count - 1 elements, it calls
setstate(failbit)...
You could check for that failbit to see if the user entered more data than the buffer allows?
You can use c++ methods..
std::string somestring;
std::cout << "Enter Animal Name: ";
std::cin >> somestring;
printf("someString = %s, and its length is %lu", somestring.c_str(), strlen(somestring.c_str()));
you can also use more c++ methods
std::string somestring;
std::cout << "Enter Animal Name: ";
std::cin >> somestring;
std::cout << "animal is: "<< somestring << "and is of length: " << somestring.length();
I guess you could do something with cin to a stringstream to get around the way that cin exctract works.
Consider the following program:
#include <iostream>
#include <string>
#include <limits>
// The easy way
std::string f1() {
std::string result;
do {
std::cout << "Enter Animal Name: ";
std::getline(std::cin, result);
} while(result.size() == 0 || result.size() > 20);
return result;
}
// The hard way
void f2(char *panimal_name) {
while(1) {
std::cout << "Enter Animal Name: ";
std::cin.getline(panimal_name, 20);
// getline can fail it is reaches EOF. Not much to do now but give up
if(std::cin.eof())
return;
// If getline succeeds, then we can return
if(std::cin)
return;
// Otherwise, getline found too many chars before '\n'. Try again,
// but we have to clear the errors first.
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n' );
}
}
int main () {
std::cout << "The easy way\n";
std::cout << f1() << "\n\n";
std::cout << "The hard way\n";
char animal_name[20];
f2(animal_name);
std::cout << animal_name << "\n";
}
Use a larger buffer for user input and check for the last element of your buffer.