cin.getline() is removing the first letting of my input in C++ - c++

When I use this following code, the first string input is displayed correctly, but every string input afterwards is missing the first letter.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
//declare arrays
string cd_Name[20] = {""};
string cd_Artist[20]= {""};
//declare variables
int numCD = 0;
cout << "Enter number of CD's: ";
cin >> numCD;
if (numCD <= 20)
{
for (int x = 0; x < numCD; x++)
{
cout << "Enter name of CD " << x + 1 << ": ";
cin >> cd_Name[x];
cin.ignore();
getline(cin, cd_Name[x]);
cout << "Enter the artist of " << cd_Name[x] << ": ";
cin.get();
getline(cin, cd_Artist[x]);
cout << endl;
}//end of for loop
cout << "CD Names Artists" << endl;
cout << "======== =========" << endl;
for (int x = 0; x < numCD; x++)
{
cout << cd_Name[x] <<" "<< cd_Artist[x] << endl;
}//end of for loop
}
else
cout << "You can only enter a Max of 20 CD's" << endl;
//end of if
system ("pause");
return 0;
}//end of main function
An example of the output is shown below:
Enter the number of CD's: 3
Enter name of CD 1: The Battle of Los Angeles
Enter the artist of The Battle of Los Angeles: Rage Against the Machine
Enter name of CD 2: So Far So Good
Enter the artist of o Far So Good: Brian Adams
Enter name of CD 3: Amarte es un Placer
Enter the artist of marte es un Placer: Luis Miguel
CD Names Artists
========= ==========
The Battle of Los Angeles ise Against the Machine
o Far So Good rian Adams
marte es un Placer uis Miguel

I believe you will find this is caused by the cin.ignore() call.
the .ignore() of the istream base class functions by
Extract[ing] characters from the input sequence and discard[ing] them
The default value is to discard One (1) character.
In short,
cin >> cd_Name[x];
cin.ignore();
getline(cin, cd_Name[x]);
Will get the name inputted by the user, Ignore the first character, then extract the string to your array.
If you called cin.ignore(2) it would remove the first two characters, and so on.
Please view this article for more information (http://www.cplusplus.com/reference/istream/istream/ignore/)
[EDIT]
You may find your getline and ignore calls are arbitrary
try using this in your loop:
cin will deliver the resulting string directly into the variable given, you should not need getline, nor ignore to achieve this.
char Name_tmp[50];
char Artist_tmp[50];
for (int x = 0; x < numCD; x++)
{
cout << "Enter name of CD " << x + 1 << ": ";
cin.get(Name_tmp, 50); //get 50 character (max length of string) into string variable
cout << "Enter the artist of " << cd_Name[x] << ": ";
cin.get(Artist_tmp, 50); //get 20 character (max length of string) into string variable
cout << endl;
cd_Name[x] = Name_tmp;
cd_Artist[x] = Artist_tmp;
}//end of for loop
In short, I'm extracting a set number of characters (less can be taken, but no more) from the users input into a temporary C-string, then assigning those values into your array.
Note, I made use of the istream::get method.
[Edit 2]
I noticed David Schwartz's post as to the implementation of using
system ("pause");
Unfortunately, I believe David is an avid linux programmer, and is not familiar with Visual Studio - When a program in run from VS (unless done so without debugging) the program output window closes before you can view the results.
This may also occur with some other IDE's.
My recommendation is to use something like this instead
char tmp[20];
cin.get(tmp, 20);
return;
This will pause and wait for the user to provide some input (a return should count as input in the case of MS Visual Studio)

Related

Having difficulty obtaining double after using getline() in for loop

I am trying to create a program which obtains names and test scores and places them into separate vectors. I am using getline() so I can get both first and last names. However, whenever I use the below code every name after the first loses its first letter. So, if the input for names was John Smith, Jane Smith, Jacob Smith, etc. The program outputs John Smith, ane Smith, acob Smith,... I tried taking out the cin.ignore()'s but then the program runs through after the first entry. I also tried creating separate functions for obtaining the names and scores, but this did not work either. Any advice or help would be appreciated.
int main() {
string test_taker;
int num_of_students = 0;
cout << "How many students took the exam? ";
cin >> num_of_students;
int starting = 0;
vector <double> score_list_us(num_of_students);
vector <string> name_list_us(num_of_students);
vector<double> score_list_sorted(num_of_students);
vector<string> name_list_sorted(num_of_students);
for (int i =0; i < num_of_students; i++) {
cout << "Student #" << i + 1 << " Name: ";
cin.ignore();
getline(cin, name_list_us[i]);
cout << "Student #" << i + 1 << " Score: ";
cin >> score_list_us[i];
cin.ignore();
}...
Problem: Missing character
See that cin.ignore(); right in front of getline(cin, name_list_us[i]);? Guess what it does.
On the first pass through the loop that cin.ignore(); eats the newline left by cin >> num_of_students; Every other time through the loop there is no newline to be eaten, so it eats part of your data.
Solution
Always put ignore()s, if you can't avoid them entirely, AFTER the operation that left the garbage you want gone. If you put ignore() before another operation, sooner or later you're going to hit that operation without garbage in the stream. In this case you hit it sooner.
Next, you want to ignore() everything up to and including the newline. Anything the user typed in after the input we want is garbage and should be discarded. Otherwise ignore() takes out a space character or something equally useless and leaves the newline for getline to trip over. I'll leave it to an old friend to explain what you need to do.
Specifically, use
cin.ignore(numeric_limits<streamsize>::max(), '\n');
So
int main() {
string test_taker;
int num_of_students = 0;
cout << "How many students took the exam? ";
cin >> num_of_students;
// ignore after
cin.ignore(numeric_limits<streamsize>::max(), '\n');
int starting = 0;
vector <double> score_list_us(num_of_students);
vector <string> name_list_us(num_of_students);
vector<double> score_list_sorted(num_of_students);
vector<string> name_list_sorted(num_of_students);
for (int i =0; i < num_of_students; i++) {
cout << "Student #" << i + 1 << " Name: ";
// not before
getline(cin, name_list_us[i]);
cout << "Student #" << i + 1 << " Score: ";
cin >> score_list_us[i];
// because this guy eats the newlines
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}

Transversing an Array of structs error in C++

Current code:
const int MAX_CODENAME = 25;
const int MAX_SPOTS = 5;
struct Team {
string TeamName[MAX_CODENAME];
short int totalLeagueGames;
short int leagueWins;
short int leagueLoses;
};
//GLOBAL VARIABLES:
Team league[MAX_SPOTS];
void addTeams(){
int i = 0; //first loop
int j; //second loop
while(i < MAX_SPOTS){
cout << "****** ADD TEAMS ******" << endl;
cout << "Enter the teams name " << endl;
scanf("%s", league[i].TeamName) ;
}
void searchTeam(){
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
for(int i = 0; i < MAX_SPOTS; i++){
if(decider == league[i].TeamName){
cout << endl;
cout << league[i].TeamName << endl;
break;
}else{
cout << "Searching...." << endl;
}
}
}
I really dont know why its not working but I have included all the perquisite header files such as and but the program crashes when i enter the data and then attempt to search. I get the circle of death and then program not responding then says Process returned 255 (0xFF) . It does not even out put Searching.... the program practically gives up as soon as I enter that name.
Also if this can be optimized by the use of pointers that would be great.
tl;dr run-time error causing the search to fail as soon as i type in a name. And for the record I have checked to make sure the name I entered is valid.
scanf doesn't know about std::string. Use std::cin >> league[i].TeamName.
scanf("%s", league[i].TeamName) ;
This should be changed to
std::cin >> league[i].TeamName ;
A couple of other things here....
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
Every time you input a value, you are telling the computer to hold the inputted value at decider[25] but the computer only reads indexes 0-24.
if(decider == league[i].TeamName){
Which array slot are you comparing the team name to? If its the 25th element than the statement should be
if(decider[24] == league[i].TeamName){
Pointers are better suited if the number of TeamNames are unknown. Based on the limited code presented, I highly recommend you stay within the realm of basic data types. For the purposes of troubleshooting, please post your full code in the future.
Your TeamName member variable:
string TeamName[MAX_CODENAME];
is an array of 25 strings, so in this line:
scanf("%s", league[i].TeamName) ;
you are courrupting the array. You don't really want an array anyways, so change the TeamName declaration to:
string TeamName;
and then when you read the name, you'll need to use iostreams which knows how to populate a string type (scanf only works with c char arrays):
std::cin >> league[i].TeamName

do loop statement is causing an infinite loop

I am writing a library program that displays a menu of options letting the user add new books to the library, but in my add statement it accepts the title and then gets caught in an infinite loop. I wrote a book class that mainly uses pointers to assign things, if I need to post that I will. But when you run the program it compiles, displays the menu, and when you choose add a book it accepts the title but as soon as you hit enter it starts an a infinite loop.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int main()
{
int bookCounter = 0;
Book library[25];
int menuOption = 0;
char tempt[50] = "\0";
char tempauth[50] = "\0";
char search[50] = "\0";
unsigned int tempp = 0;
do
{
menuOption = 0;
cout << endl << "1. Show the Library" << endl;
cout << "2. Add a Book" << endl;
cout << "3. Search the Library by Title" << endl;
cout << "4. Exit Library" << endl;
cout << "Select a menu option (e.g. 1, 2, etc.): ";
cin >> menuOption;
if(menuOption == 1)
{
for(int i = 0; i < bookCounter; i++)
{
library[i].displayBook();
}
}
else if(menuOption == 2)
{
cout << "Enter the Title: ";
cin >> tempt[50];
cout << endl << "Enter the Author's name: " ;
cin >> tempauth[50];
cout << endl << "How many pages does the book have? (just enter a number, e.g. 675, 300): ";
cin >> tempp;
library[bookCounter].setAuthor(tempauth);
library[bookCounter].setTitle(tempt);
library[bookCounter].setPages(tempp);
bookCounter++;
menuOption = 0;
}
else if(menuOption == 3)
{
cout << "Enter a title you would like search for (will return partial matches): ";
cin >> search[50];
for (int i = 0; i < bookCounter; i++)
{
int temp = strcmp(search, library[i].getTitle());
if (temp == 1)
{
library[i].displayBook();
}
}
}
}while(menuOption != 4);
system("pause");
return 0;
}
The problem is caused by the way you are trying to read into the arrays:
cin >> tempt[50];
This tries to read a single character into the character at index 50 of the array tempt, which is outside the bounds of the array (which has valid indices in the range [0,49]).
This means only the first character of the entered title will be consumed from the output. Similarly for author. Hence, only the first two characters which you have entered are actually read. Then, this line will be encountered:
cin >> menuOption;
Here, what is left in the buffer (the remainder of the title) will be read, expecting a number. As this does not match a valid format for a number, you will get an error flag in cin. This will mean that all resulting inputs will also fail, menuOption will never change and your program gets stuck in a loop.
A solution to your problem would be to read into tempt without index. You can also check if a read has failed using if(cin.fail()) which should only trigger if there's been an error. If so, handle it and then call cin.clear() to reset the error flags.
I think that this line cause the problem,
cin >> search[50];
You're accessing out bound of search array.
One error is when you type in the menu option, the 'return' stays in the input buffer. The next read of char[] in your tempt variable, will be skipped.
Type cin.ignore(); after cin >> menuOption;
Also, you should read tempt instead instead of tempt[50].
This
cin >> tempt[50];
accesses a non-existent entry in the array. You probably meant to code
cin >> tempt;
Or, better, use std::string instead of raw char array.

(cin >> int).get() doesn't properly work in Xcode(4.3.3)

I'm currently working on the book "C++ Primer Plus" and doing some of the programming excersis.
As it seems, I'm having a problem with Xcode(4.3.3) because following code doesn't work how it's supposed to work:
#include <iostream>
#include <string>
struct car
{
std::string maker;
int year;
};
int main()
{
using namespace std;
cout << "How many cars do you wish to catalog? ";
int nCars;
(cin >> nCars).get();
car* aCars = new car[nCars];
for (int i = 0; i < nCars; i++)
{
cout << "\nCar #" << (i + 1) << endl;
cout << "Please enter the make: ";
getline (cin, (aCars + i)->maker);
cout << "\nPlease enter the year made: ";
(cin >> (aCars + i)->year).get();
}
cout << "Here is your collection: \n";
for (int i = 0; i < nCars; i++)
{
cout << (aCars + i)->year << " " << (aCars + i)->maker << endl;
}
delete [] aCars;
return 0;
}
The problem is, I don't have the chance to enter any maker. The program directly goes to the point where I have to enter the year, even though I'm using "(cin >> nCars).get();" to get rid of the newline character.
Am I overlooking something?
Thanks in advance!
I suspect that you may be running on windows and the two-byte newlines are hitting you. You may be able to improve things (for lines that aren't ridiculously long) with ignore:
cin >> nCars;
cin.ignore(1024, '\n');
Note that since you rely on stream numeric processing, entering a non-numeric year such as QQ will result in the programming just finishing without asking for any more input.
You don't need to do math on the years so treat them as strings instead of integers. Then if you need to you can do validation of each year after you get the input.
Ok, guys..I found the problem.
The console within Xcode doesn't work as expected when using cin.get().
I tried the same code in the terminal as well as with Visual Studio (Win 7) and the program works perfectly.
Anyway, thank you all for your advices. I'll try consider them the next time. :)
Cheers!

C++ Noobie - Why does moving these lines break my application?

This is my first attempt at C++, following an example to calculate a tip through a console application. The full (working code) is shown below:
// Week1.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
// Declare variables
double totalBill = 0.0;
double liquour = 0.0;
double tipPercentage = 0.0;
double totalNoLiquour = 0.0;
double tip = 0.0;
string hadLiquour;
// Capture inputs
cout << "Did you drink any booze? (Yes or No)\t";
getline(cin, hadLiquour, '\n');
if(hadLiquour == "Yes") {
cout << "Please enter you booze bill\t";
cin >> liquour;
}
cout << "Please enter your total bill\t";
cin >> totalBill;
cout << "Enter the tip percentage (in decimal form)\t";
cin >> tipPercentage;
// Process inputs
totalNoLiquour = totalBill - liquour;
tip = totalNoLiquour * tipPercentage;
// Output
cout << "Tip: " << (char)156 << tip << endl;
system("pause");
return 0;
}
This works fine. However, I want to move:
cout << "Please enter your total bill\t";
cin >> totalBill;
to be the first line under:
// Capture inputs
But when I do the application breaks (it compiles, but just ignores the if statement and then prints both cout's at once.
Im scratching my head becuase I cant understand what's going on - but I'm assuming I'm being an idiot!
Thanks
Try this
// Capture inputs
cout << "Please enter your total bill\t";
cin >> totalBill;
cin.clear();
cin.sync();
See c++ getline() isn't waiting for input from console when called multiple times
Or, better yet don't use getline at all:
cout << "Please enter your total bill\t";
cin >> totalBill;
cout << "Did you drink any booze? (Yes or No)\t";
cin >> hadLiquour;
totalBill is a number, i.e. the program "consumes" everything from your input that is a number. Let's say you entered:
42.2[RETURN]
The 42.2 gets copied into totalBill. The [RETURN] doesn't match, and remains in the input buffer.
Now, when you call getline(), the [RETURN] is still sitting there... I am sure you can figure out the rest from there.
Cin doesn't remove the newline character from the stream or do type-checking. So using cin>>var; and following it up with another cin >> stringtype; or getline(); will receive empty inputs. It's best practice to NOT MIX the different types of input methods from cin.
[for more informations see link]
you may change your code as below :
cout << "Please enter your total bill\t";
getline(cin, hadLiquour); // i used the hadLiquour string var as a temp var
// so don't be confused
stringstream myStream(hadLiquour);
myStream >> totalBill;