[Resolved] Basic I/O problem in C++

This topic is 3368 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Resolved Hi there i am writing a program to write user inputted data to a database running in a loop but everytime it runs the loop more than once you dont get a chance to enter the first set of information and it goes straight to the second set of information eventho they are both using the same function to get the input heres what i get when i run the program: image my code is in a later post any help would be greatly appreciated [Edited by - OpperationQuak on October 29, 2008 7:22:38 AM]

Share on other sites
You're making a basic problem very complicated. My advice is to just use cin directly instead of getInput, until you find yourself with duplicated code that needs to be factored out.

Share on other sites
i understand that it does look like im making a simple problem complicated but the program as a whole isnt just going to write a database

also if i just use cin i will never find the problem and therefore wont learn what i have done wrong

Share on other sites
Quote:
 Original post by OpperationQuaki understand that it does look like im making a simple problem complicated but the program as a whole isnt just going to write a database
The only thing that your getInput fnction accomplishes is to needlessly complicate a very simple problem. Here is a simple refactoring of your code, with no need for get input, no need for a separate parsing structure, and simpler to boot:
	do	{		input userInput;		cout << "Enter Name: "		getline(cin, custDetails.name);		cout << "Enter Address: "		getline(cin, custDetails.address);		cout << "Enter Phone Number: "		getline(cin, custDetails.phoneNum);		cout << "Enter D.O.B: "		cin >> custDetails.dob;				cin >> std::boolalpha >> cont;	}	while(cont == true);

Share on other sites
i get what your saying and i know i could do that but i want to find out whats causeing the problem with the function

if i make it an infinite loop and stop getting the date and continue prompt it works fine so it something to do with one of the 3 lines of code im omiting

anyone have any ideas without telling me to stop using getInput?

Share on other sites
i managed to get it to work by taking getline out but now i need an alternative to getline

any solutions

Share on other sites
#define NAME_MAX 256#define ADDR_MAX 256struct Customer{   char Name[NAME_MAX];   char Address[ADDR_MAX];   int PhoneNo;   int DOB;};void prompt(const char* msg, bool newLine = true){   if(newLine)   {      cout << msg;   }   else   {      cout << msg << "\n";   }}bool GetEntry(Customer* customer){   prompt("Enter Name: ");   cin.getline(customer->Name, NAME_MAX);   prompt("Enter Address: ");   cin.getline(customer->Address, ADDR_MAX);   prompt("Enter Phone Number: ");   cin >> customer->PhoneNo;   prompt("Enter D.O.B: ");   cin >> customer->DOB;   bool r_val;   cin >> rVal;}int main(){   while(true)   {      Customer c;      if(!GetEntry(&c))         break;   }}   return r_val;}

[Edited by - staticVoid2 on October 24, 2008 4:48:26 PM]

Share on other sites
that doesnt work either staticVoid
it still has the same problem
witch sugests more that its a problem with getline
or the way im using it

Share on other sites
I dunno then, maybe you could try reformatting your hard drive. or did you miss any semi-colons?, that could effect runtime performance.

Share on other sites
LOL craig
just lol

but seriously this is a pain in the arse

Share on other sites
cin.ignore()?
Only a string input will take off the newline character from the input stream. You prolly have a newline on the input stream, causing the first question to process that newline, making it look like you went to the second question.

Share on other sites
i tryed using cin.ignore() but that doesnt do what i want it to
its defo something todo with getline

is there an altenative to getline?

Share on other sites
getting a line means getting a character string until finding a newline character, so, as KulSeran points out, you need to find how that \n character gets in places where you don't want it to be. Happend hell a lot of times to me while doing very very simple programs at university.

Share on other sites
std::getline(std::istream &, std::string &) is most certainly not the problem. Can you post a compilable, minimal example where getline fails to do what you want it to do?

Share on other sites
@wlw_wl: i tryed using cin.ignore(256,'\n'); but all i got was having to press enter twice and then when it looped i still got nothing from enter name

@rip-off: here is my full code listing

main.cpp
#include <iostream>#include <fstream>#include <string>#include "struct.h"#include "io.h"using namespace std;int main(){	person custDetails;	bool cont;	ofstream dbFile("C:\\Users\\James\\Desktop\\customers.dat",ios::out);	do	{		custDetails.name = getString("Enter Name: ",false);		custDetails.address = getString("Enter Address: ",false);		custDetails.phoneNum = getInput<int>("Enter Phone Number: ");		custDetails.dob = getDate("Enter D.O.B: ",false);		cont = getInput<bool>("Continue? ");		dbFile << custDetails.name << endl << custDetails.address << endl << custDetails.phoneNum << endl;		dbFile << custDetails.dob.day << " " << custDetails.dob.month << " " << custDetails.dob.year << endl;	}	while(cont == true);	dbFile.close();	return 0;}

io.h
#ifndef IO_H#define IO_H	#include <iostream>	#include <fstream>	#include <string>	#include "struct.h"	using namespace std;	template <class tInput,class tSInput>	tInput getInput(tSInput prompt)	{		tInput usrInput;		cout << prompt;		cin >> usrInput;		//getline(cin,usrInput);		//cin.ignore(256,'\n');		return usrInput;	}	string getString(string prompt,bool newLine)	{		string usrString;		prompt.append(newLine?"\n":"");		cout << prompt;		getline(cin,usrString);		return usrString;	}	date getDate(string prompt,bool newLine)	{		date usrDate;		prompt.append(newLine?"\n":"");		cout << prompt;		cin >> usrDate.day;		cin >> usrDate.month;		cin >> usrDate.year;		return usrDate;	}#endif

struct.h
#ifndef STRUCT_H#define STRUCT_H	#include <iostream>	#include <fstream>	#include <string>	#include "io.h"	using namespace std;	struct date{		int day,month,year;	};	struct person{		string name,address;		int phoneNum;		date dob;	};	#endif

hope that helps

Share on other sites
really all I see is that possibly something is left in the buffer,
try using ostream& flush ( ostream& os ); (before attempting to read name)
as referenced here:
http://www.cplusplus.com/reference/iostream/manipulators/flush.html

Share on other sites
Quote:
 Original post by wlw_wlreally all I see is that possibly something is left in the buffer,try using ostream& flush ( ostream& os ); (before attempting to read name)as referenced here:http://www.cplusplus.com/reference/iostream/manipulators/flush.html

i tryed using cout.flush(); in lots of different places but its not changing a single thing i still dont get a chance to input data for the name anytime after the first itteration of the loop

Share on other sites
Mixing std::getline() with non-getline input can be confusing. std::getline() removes the newline from the stream, while other input methods will parse up to the newline, and the next call skips the newline.

Here is how I would write your program:
// struct.h#ifndef STRUCT_H#define STRUCT_H// only include files that are necessary for this header to compile//#include <iostream>//#include <fstream>#include <string>#include <iosfwd>// Don't use "using" directives in header files// using namespace std;// While this is not universal:// A common naming convention for types is to make the first letter in every word// uppercase. This makes it easy to find a name for a variable of that type.// Just make the first letter lowercase// Example: class Foo -> variable name "foo"//          class Date -> variable name "date"//          class QuiteLong -> variable name "quiteLong"struct Date{	int day, month, year;};// These functions allow us to write and read "Date" instances from streamsstd::ostream &operator<<(std::ostream &, const Date &);std::istream &operator>>(std::istream &, Date &);struct Person{	std::string name, address;	int phoneNum;	Date dob;};std::ostream &operator<<(std::ostream &, const Person &);std::istream &operator>>(std::istream &, Person &);	#endif// struct.cpp#include "struct.h"std::ostream &operator<<(std::ostream &out, const Date &date){	return out << date.day << ' ' << date.month << ' ' << date.year;}std::istream &operator>>(std::istream &in, Date &date){	return in >> date.day >> date.month >> date.year;}std::ostream &operator<<(std::ostream &out, const Person &person){	return out << person.name << ' ' << person.address << ' ' << person.phoneNum << ' ' << person.dob;}std::istream &operator>>(std::istream &in, Person &person){	return in >> person.name >> person.address >> person.phoneNum >> person.dob;}// io.h#ifndef IO_H#define IO_H#include <string>#include <sstream>#include <iostream>#include <stdexcept>// Use meaningful type names// What is a tSInput?// Also, the "t" prefix is pointless.// The function is so small that the use is obvious.// Finally, now that we have fully templated this// and overloaded operator >> for Date// We no longer need getDate() or getString()// Also, the "newline" boolean argument isn't (IMO) required.// The caller has control over the prompt, they can specify the newline there if they want.// I think that getInput<int>("Enter a number\n"); is more intuitive than// getInput<int>("Enter a number",true);template <class Result, class Prompt>Result getInput(const Prompt &prompt){	// A std::stream object, used in a boolean context will	// evaluate to true while it hasn't had an error	// Examples of errors are failed reads	// e.g. std::cin >> integer and the user inputs "abc"	// Or the end of the stream was reached.	while(std::cin)	{		std::cout << prompt;		Result result;		std::string line;		std::getline(std::cin,line);		// stringstream does exactly what it says		// It is a std::stream, but backed by a memory buffer (a string)		// We construct it with the line we just read.		// Alternatively, we could have done this:		// std::stringstream stream;		// stream << stuff;		// This works even when "stuff" isn't a std::string		std::stringstream stream(line);		// Again, we are testing a stream in a boolean context.		// Remember operator>>(std::istream &, Foo &) returns the stream it was passed.		if( stream >> result )		{			return result;		}		else		{			std::cerr << "Please try again.\n";		}	}		// if we get here, std::cin has failed	// We can't really return an error, because not all "Result" types	// would have a state that is an error.	throw std::runtime_error("std::cin failed");}#endif// main.cpp#include <iostream>#include <fstream>#include <string>#include "struct.h"#include "io.h"int main(){	bool cont;	std::ofstream file("data.txt");	do	{		// simpler names are better and easier to parse visually		// So "person", not "custDetails".		// Also, scope variables as tightly as possible		Person person;		// We could just use std::cin >> person, because we defined that operator.		// But then we can't provide the nice promts.		// However, because that function is implemented it will save us time when		// we go to read the file later...		person.name = getInput<std::string>("Enter Name: ");		person.address = getInput<std::string>("Enter Address: ");		person.phoneNum = getInput<int>("Enter Phone Number: ");		person.dob = getInput<Date>("Enter D.O.B (dd mm yy): ");		file << person << '\n';		// only use "endl" when you really want the stream *flushed*		// Otherwise just use '\n'		//		//dbFile << person.name << endl << person.address << endl << person.phoneNum << endl;		//dbFile << person.dob.day << " " << person.dob.month << " " << person.dob.year << endl;		// getInput<bool>: not intuitive		char c = getInput<char>("Continue? (y/n) ");		// This is shorter than		// if(c == 'y')		// {		//     cont = true;		// }		// else		// {		//     cont = false;		// }		cont = (c == 'y');	}	while(cont == true);	// std::fstream's close themselves on destruction	// dbFile.close();	// main() is special: it doesn't need to explicitly return a value.	// It will act as though you write return 0; unless you specify otherwise.	// return 0;}

Share on other sites
i got it fixed
all i had to do was add the following line after code using cin instead of getline

char c = cin.get();

thanks for everyones help with this anyway