Sign in to follow this  
OpperationQuak

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

Recommended Posts

OpperationQuak    122
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 this post


Link to post
Share on other sites
theOcelot    498
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 this post


Link to post
Share on other sites
OpperationQuak    122
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 this post


Link to post
Share on other sites
swiftcoder    18426
Quote:
Original post by OpperationQuak
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
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 this post


Link to post
Share on other sites
OpperationQuak    122
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 this post


Link to post
Share on other sites
staticVoid2    381


#define NAME_MAX 256
#define ADDR_MAX 256

struct 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 this post


Link to post
Share on other sites
KulSeran    3267
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 this post


Link to post
Share on other sites
wlw_wl    146
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 this post


Link to post
Share on other sites
OpperationQuak    122
@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 this post


Link to post
Share on other sites
wlw_wl    146
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 this post


Link to post
Share on other sites
OpperationQuak    122
Quote:
Original post by wlw_wl
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


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 this post


Link to post
Share on other sites
rip-off    10976
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 streams
std::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 this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this