i have a simple code that gets name of user as an array with getline() public function. when it reaches to char '$' i want to stop getting input from user and go to next line.but immediately after reaching char'$'(my delimiter)it ignores line 5 and runs line 6 and i don't know why!!!
#include <iostream> // std::cin, std::cout
int main () {
char name[256], title[256];
std::cout << "Please, enter your name: ";
std::cin.getline (name,256,'$'); //Line 3
std::cout << "Please, enter your favourite movie: ";
std::cin.getline (title,256); // Line 5
std::cout << name << "'s favourite movie is " << title; // Line 6
return 0;
}
Let me guess your input looks like this:
> ./myProg
Please, enter your name: noob$
lease, enter your favourite movie: Top Gun
noob's favourite movie is
>
Here we see that you entered: noob$<return> followed by Top Gun<return>.
The problem is that the input the computer is seeing is:
noob$\nTop Gun\n
OK. So what is happening in the code.
std::cin.getline (name,256,'$'); // This reads upto the '$' and throws it away.
So your input stream now looks like:
\nTop Gun\n
Notice the '\n' at the front of the stream.
Now your next line is:
std::cin.getline (title,256); // This reads the next line.
// But the next line ends at the next new line
// which is the next character on the input stream.
// So title will be empty.
To fix it you need to read off that empty line.
A better way to fix it is to not require the name to be terminated by '$'. User input is usually better done a line at a time. As the user hits return the buffer is flushed and the stream actually starts working. The program is not doing anything (apart from waiting) until that buffer is flushed to the stream (this is usally on return but can happen if you just type a lot).
It seems to work like this:
#include <iostream> // std::cin, std::cout
int main () {
char name[256], title[256], endOfLine[2];
std::cout << "Please, enter your name: ";
std::cin.getline (name,256,'$'); //Line 3
std::cin.getline(endOfLine, 1);
std::cout << "Please, enter your favourite movie: ";
std::cin.getline (title,256); // Line 5
std::cout << name << "'s favourite movie is " << title; // Line 6
return 0;
}
You can use the following solution to solve your problem:
.....getline(title,256,'$')
// ^
// |
// this is where the delimiter goes in your function call
Related
I am not sure where I put the char command declaration where I wont get a "Not defined in this scope" error and it will loop through accepting a new char command the next time the program loops.
I tried putting it inside of the do loop but then it said that char was not defined in that scope, I then put it right after the int main function and when entering A as a command it infinitely loops my add_entry function without allowing user input.
Do I have to pass by reference maybe? Or pass by value?
My file that holds all function definitions
#include "main.h"
using namespace std;
int syntax::add_entry()
{
cout << "Enter a concept name: ";
cin.get(name, SIZE);
cout << endl << "Enter an example of the syntax: ";
cin.get(example,SIZE);
cout << endl << "Enter a description of the syntax: ";
cin.get(desc,SIZE);
cout << endl << "Enter a difficulty rating from 1-10: ";
cin.get(diff,SIZE);
cout << endl << "Enter a usefulness rating from 1-10: ";
cin.get(use,SIZE);
//open and write to the file
ofstream myfile;
myfile.open("data.txt");
myfile << "Name: " << name << endl;
myfile << "Example of syntax: " << example << endl;
myfile << "Description of syntax: " << desc << endl;
myfile << "Difficulty rating from 1-10: " << diff << endl;
myfile << "Usefulness rating from 1-10: " << use << endl;
myfile.close();
return 0;
}
int syntax::display_entry()
{
ifstream myfile("data.txt");
/*
char name[SIZE];
char example[SIZE];
char desc[SIZE];
char diff[SIZE];
char use[SIZE];
*/
if(myfile.is_open())
{
while(myfile >> name >> example >> desc >> diff >> use)
{
std::cout << name << ", " << example << ", " << desc << ", " << diff << ", " << use;
}
myfile.close();
}else
cout << "File is not open" << endl;
std::cin.get();
return 0;
}
my main .cpp file
#include "main.h"
using namespace std;
int main()
{
char command;
syntax c;
do{
cout << "Welcome to the C++ concept syntax user database." << endl;
cout << "Choose one of the following commands: " << endl;
cout << endl << endl;
cout << "A) Add a new entry B) Display all entrys C) Search for difficulty D) Exit: ";
cin >> command;
cout << endl;
if(command == 'A' || command == 'a')
{
c.add_entry();
}
else if(command == 'B' || command == 'b')
{
c.display_entry();
}
else if(command == 'D' || command == 'd')
{
cout << "Quitting program, Thank you for using" << endl;
}
}while(command != 'D' || command != 'd');
return 0;
}
my .h file
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
class syntax
{
public:
const static int SIZE = 50;
char name[SIZE];
char example[SIZE];
char desc[SIZE];
char diff[SIZE];
char use[SIZE];
int display_entry();
int add_entry();
private:
};
You need to read and understand about "formatted input" and "unformatted input". Please check here.
Formatted input is done using the extractor operator >>. It reads characters from a stream and formats them to the expected variable type. If you write int x; std::cin >> x and you enter the number 12, so the digits/characters '1' and '2', your input will be formatted / converted to an integer value 12.
It is important to understand that formatted input
ignores leading white space
stops any conversion when encountering white space (but does not extract it from the stream)
Meaning, if you enter 12 and then press the enter-key, the characters '1' and '2' will be extracted from the stream, but the newline 'n' will not be consumed or extracted from the screen and is still available.
This default behavior can be addapted by setting certain flags.
Now, if we look at "unformatted input" functions, like get, it will read all kind of characters, including spaces and so on until it hits the specified delimiter, which is '\n' per default. For the get function, the delimiter '\n' will not be extracted. So, it is still in the stream. This is in contrast to the getline function which would extract the '\n' from the stream (but not store it).
All this you can read in the linked description.
And now, the root cause for all you problems, is also written in the description:
If no characters were extracted, calls setstate(failbit)
Then, let us look on the order of events
You enter a 'a', becuase you want to add an entry
The 'a' will be extracted and the '\n' is still in the stream
In function "add_entry" you call "get"
Get will try to read charcters, until it finds a newline '\n'
But, as a leftover from the previous operation, it will immediately see the '\n' , and hence store no other data at all, and consequently sets the failbit of the stream. All the following calls to std::cin will do nothing, because the failbit of the stream is set.
The functions returns to main and the failbit is still set
The next call cin >> command; will do nothing and will especially not modify the "command" variable. This will still contain an 'a'
And then the loop runs forever
You have an additional bug in the "while" condition. This must be corrected to: ´while (command != 'D' && command != 'd');´
Now, what to do.
First, and very important, for any IO-function you need to check, if it worked or not. There are functions to read the iostate of the stream. But c++ makes life easier. The bool-operator and the not-operator are overwritten and will return state information. If you want to know, if any IO operation was successful, the you can write something like if (std::cin) ....
Very convenient. But must be used.
And since IO operations return mostly a reference to the stream for which they were called, you can write if (cin >> command) . . . . This will first call the extraction operator. This will return a reference to the stream and for that you can use an if statement, because of the overwritten bool-operator.
But how to overcome the nasty problem with the '\n' in the stream, which is often there? There are basically 2 functionalities:
Function ignore. Will ignore all/a number of characters, until a delimiter is hit.
Function/manipulator std::ws. Will eat all white spaces.
I recommend to add one time cin >> std::ws; at the top of your "add_entry" routine and then you must change all get functions to getline. If not, you would need to add std::ws before each get statement.
And again, for each IO function, check the status! For example if (!cin.getline(example, SIZE)) .... do something, show error
And in the future. For any transition from formatted to unformatted input, use std::ws
And, do never forget to read the documentation carefully.
Have fun!
After i run this code, it will prompt me to enter the first path e.g. c:/hello, and enter second path e.g. c:/world.
Output:
First path: c:/hello
Second path: :/world
As you can see the second path missing a c in front. But after i remove cin.get() after cout<<"Enter second path: "; it able to show the c in front. Can someone explain to me why is that so?
system("cls");
cout << "Enter first path: ";
cin.get();
getline(cin, firstPath);
cout << endl;
cout << "First path: " << firstPath << endl;
cout << endl;
cout << "Enter second path: ";
//cin.get(); // Need to be remove to shows c:/world
getline(cin, second path);
cout << endl;
cout << "Second path: " << secondPath<< endl;
cout << endl;
system("pause")
system("cls");
TL:DR; delete your cin.get(); lines
Delete cin.get(); it will read one character from cin, and so the next read from cin will read the next characters, so in the second case the "c" is being read by cin.get() and hence the next read, getline(cin, second path) will not read it (it has already been read). Why the "c" is being read after the first use of cin.get() is a mystery (perhaps you are typing a space before the "c"?
Only use cin.get() if you want to get the next character on the input stream and store it somewhere (e.g. char c = cin.get(), in this case c == 'c').
If you want to skip the current character use cin.ignore() which does the same thing as cin.get(), except you can choose how many characters to skip, and it doesn't bother returning any read characters. Either way it would be inappropriate to use these in this situation.
This question already has answers here:
Why getline skips first line?
(3 answers)
Closed 9 years ago.
I have the following code:
int data = 0;
cout << "Enter a number: ";
cin >> data;
cout << "You entered " << data << endl;
string str;
cout << "Enter a string: ";
getline(cin,str);
cout << "Your entered " << str << endl;
After getting the first prompt, I entered a valid number 10. But as soon as I hit return, the program output:
You entered 10
Enter a string: Your entered
In other words, it didn't ask for the second string input. What happened?
Thanks
std::cin >> data;
When you input the number for data, and hit the Return key to submit your input, a new line will be inserted into the stream. A new line is the default delimiter for the input stream, and when std::getline(std::cin, str) is used, the compiler will see that a new line is already in the stream, and it will stop running. To solve this, you need to ignore the offending character with std::cin.ignore:
std::cin.ignore();
std::getline(std::cin, str);
Classic problem of mixing numbers and strings on input stream. Use getline for both and parse by using stringstream.
Check out the below. The problem is that reading an integer does not read in the terminating newline. That newline is consumed when you use getline(...) and so your program exits. You need to consume that newline first.
int data = 0;
cout << "Enter a number: ";
cin >> data;
cout << "You entered " << data << endl;
string str;
cout << "Enter a string: ";
getline(cin,str); // consume endline <------------------
getline(cin,str);
cout << "Your entered " << str << endl;
When you enter 10, you're really entering "10\n", 10 plus the new line. It can depend on the OS, but basic idea of what is happening is that cin simply reads the 10 from the input buffer, and leaves the newline character. Then when your program reaches the getline part, getline reads the "\n" off the input buffer. Since "\n" is the default terminating character for getline, getline finishes and your programs keeps going.
So, at the end of your program, str contains simply "\n".
I'm trying to read in a string of text using getline. For some reason, it prints 'Please enter your selection' twice:
Please enter your selection
Please enter your selection
If I key invalid text, it loops again, and only prints the one time each loop thereafter.
while (valid == false) {
cout << "Please enter your selection" << endl;
getline (cin,selection);
// I have a function here which checks if the string is valid and sets it to true
// if it is valid. This function works fine, so I have not included it here. The while
// look breaks correctly if the user enters valid input.
}
Does anybody have any idea why this may be occurring?
Thank you
Probably there's something still in the input buffer from a previous operation when you enter the loop.
It's picked up by the getline, found to be invalid, then the loop runs again.
By way of example, let's say that, before you enter the loop, you read a single character. But, in cooked mode, you'll need to enter the character and a newline before it's actioned.
So, you read the character and the newline is left in the input buffer.
Then your loop starts, reads the newline, and deems it invalid so it then loops back to get your actual input line.
That's one possibility though, of course, there may be others - it depends very much on the code before that loop and what it does with cin.
If that is the case, something like:
cin.ignore(INT_MAX, '\n');
before the loop may fix it.
Alternatively, you may want to ensure that you're using line-based input everywhere.
Here's some code to see that scenario in action:
#include <iostream>
#include <climits>
int main(void) {
char c;
std::string s;
std::cout << "Prompt 1: ";
std::cin.get (c);
std::cout << "char [" << c << "]\n";
// std::cin.ignore (INT_MAX, '\n')
std::cout << "Prompt 2: ";
getline (std::cin, s);
std::cout << "str1 [" << s << "]\n";
std::cout << "Prompt 3: ";
getline (std::cin, s);
std::cout << "str2 [" << s << "]\n";
return 0;
}
Along with a transcript:
Prompt 1: Hello
char [H]
Prompt 2: str1 [ello]
Prompt 3: from Pax
str2 [from Pax]
in which you can see that it doesn't actually wait around for new input for prompt 2, it just gets the rest of the line you entered at prompt 1, because the characters e, l, l, o and \n are still in the input buffer.
When you uncomment the ignore line, it acts in the manner you'd expect:
Prompt 1: Hello
char [H]
Prompt 2: from Pax
str1 [from Pax]
Prompt 3: Goodbye
str2 [Goodbye]
I would use debugger (for example gdb in linux) to check why. Why make a theories when you can find out the real answer?
This question already has answers here:
Need help with getline() [duplicate]
(7 answers)
Closed 7 years ago.
Hey, I'm trying to write a program that will accept new tasks from people, add it to a stack, be able to display the task, be able to save that stack to a text file, and then read the text file. The issue comes when I am trying to accept input from the user, whenever you enter a string with a space in it, the menu to choose what to do just loops. I need a way to fix this. Any help would be greatly appreciated.
// basic file io operations
#include <iostream>
#include <fstream>
#include <stack>
#include <string>
using namespace std;
int main () {
//Declare the stack
stack<string> list;
//Begin the loop for the menu
string inputLine;
cout << "Welcome to the to-do list!" << endl;
//Trying to read the file
ifstream myfile ("to-do.txt");
if(myfile.is_open()){
//read every line of the to-do list and add it to the stack
while(myfile.good()){
getline(myfile,inputLine);
list.push(inputLine);
}
myfile.close();
cout << "File read successfully!" << endl;
} else {
cout << "There was no file to load... creating a blank stack." << endl;
}
int option;
//while we dont want to quit
while(true){
//display the options for the program
cout << endl << "What would you like to do?" << endl;
cout << "1. View the current tasks on the stack." << endl;
cout << "2. Remove the top task in the stack." << endl;
cout << "3. Add a new task to the stack." << endl;
cout << "4. Save the current task to a file." << endl;
cout << "5. Exit." << endl << endl;
//get the input from the user
cin >> option;
//use the option to do the necessary task
if(option < 6 && option > 0){
if(option == 1){
//create a buffer list to display all
stack<string> buff = list;
cout << endl;
//print out the stack
while(!buff.empty()){
cout << buff.top() << endl;
buff.pop();
}
}else if (option == 2){
list.pop();
}else if (option == 3){
//make a string to hold the input
string task;
cout << endl << "Enter the task that you would like to add:" << endl;
getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
cin.ignore();
//add the string
list.push(task);
cout << endl;
}else if (option == 4){
//write the stack to the file
stack<string> buff = list;
ofstream myfile ("to-do.txt");
if (myfile.is_open()){
while(!buff.empty()){
myfile << buff.top();
buff.pop();
if(!buff.empty()){
myfile << endl;
}
}
}
myfile.close();
}else{
cout << "Thank you! And Goodbye!" << endl;
break;
}
} else {
cout << "Enter a proper number!" << endl;
}
}
}
You have to add cin.ignore() right after options is chosen:
//get the input from the user
cin >> option;
cin.ignore();
And cin.ignore() is not necessary after your getline:
getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
//cin.ignore();
The problem is in options - if you didn't call cin.ignore() after it, options will contain end of line and loop will continue...
I hope this helps.
Don't do this:
while(myfile.good())
{
getline(myfile,inputLine);
list.push(inputLine);
}
The EOF flag is not set until you try and read past the EOF. The last full line read read up-to (bit not past) the EOF. So if you have have zero input left myfile.good() is true and the loop is enetered. You then try and read a line and it will fail but you still do the push.
The standard way of reading all the lines in a file is:
while(getline(myfile,inputLine))
{
list.push(inputLine);
}
This way the loop is only entered if the file contained data.
Your other problem seems to stem from the fact that you have:
std::getline(std::cin,task); // THIS is OK
std::cin.ignore(); // You are ignoring the next character the user inputs.
// This probably means the next command number.
// This means that the next read of a number will fail
// This means that std::cin will go into a bad state
// This means no more input is actually read.
So just drop the cin.ignore() line and everything will work.
Instead of using ">>" directly on your stream you might consider using getline and then attempting to fetch your option from that. Yes, it's less "efficient" but efficiency isn't generally an issue in such situations.
You see, the problem is that the user could enter something silly here. For example, they could enter something like "two", hit enter, and then your program is going to pitch a fit as it happily continues trying to decipher an empty option over and over and over and over again. The user's only recourse the way you have it set up (and the way those recommending use of ignore() are recommending) is to kill your program. A well behaved program doesn't respond in this way to bad input.
Thus your best option is not to write brittle code that can seriously break down with the most modest of user ignorance/malfunction, but to write code that can handle error conditions gracefully. You can't do that by hoping the user enters a number and then a newline. Invariably, someday, you'll bet poorly.
So, you have two options to read your option. First, read a full line from the user, make sure the stream is still good, and then turn the string you get into a stream and try to read your integer out of it, making sure this other stream is still good. Second option, attempt to read a number, verify that the stream is still good, read a line and make sure the stream is still good and that your string is empty (or just ignore it if it isn't, your choice).
#Vladimir is right. Here is the mechanism behind the bug:
When you enter option '3', what you actually put into stream is "3\n". cin >> option consumes "3" and leaves "\n". getline() consumes "\n" and your call to ignore() after getline() waits for user input.
As you can see, teh sequence of events is already not what you expected.
Now, while ignore() is waiting for input, you type in your line. That line you're typing is what will go to "cin >> option.
If you just give it one symbol, ignore() will dispose of it for you, and option will be read correctly. However, if you give it non-numeric symbols, stream will set failbit when trying to read the option. From that point on, your stream will refuse to do anything. Any << or getline will not set any new values in the variables they are supposed to change. You'll keep 3 in option and "" in task, in a tight loop.
Things to do:
always check cin.eof(), cin.fail() and cin.bad().
always initialize your variables and declare them in the narrowest scope possible (declare option=0 right before it's read).
I just figured out a way to kind of hack through it, not the greatest but it works. Create a character array, and then accept input in the array, and then put everything into the array into the string.
char buff[256];
cout << endl << "Enter the task that you would like to add:" << endl;
cin >> task;
task += " ";
cin.getline(buff, 256);
for(int i = 1; buff[i] != 0; i++){
task += buff[i];
}