I'm just starting to learn c++ and in this whole pointer / arrays chapter I'm trying to code something to get a grip on those concepts. What I want my code to do is: 1) ask for a number of students, 2) ask for a name for each student, 3) assign an ID and name to this student in a struct, 4) print the student ID and names for verification.
The problem is the following.
Let's say for example I choose to type 3 students and type the following names:
JOHN
GEORGE
NICK
What the program prints back as student ID/Names will be:
0 JOHN
1 EORGE
2 ICK
It seems to cut the first letter of all names but the first one.
#include <iostream>
using namespace std;
struct STUDENT
{
char chName[256];
int nID;
};
int main(){
//array tests
int i=0;
int nLoops=0; //number entered by user
STUDENT *pnStudents; //pointer to our student array
cout << "Enter number of students: ";
cin >> nLoops;
pnStudents = new STUDENT[nLoops];
for (i=0 ; i < nLoops ; i++)
{
cout << endl << "Full Name of Student " << i <<": ";
cin.ignore();
cin.getline(pnStudents[i].chName,255);
pnStudents[i].nID=i;
}
for (i=0 ; i < nLoops ; i++)
{
cout << pnStudents[i].nID << " " << *pnStudents[i].chName << endl;
}
system("pause");
return 0;
}
for (i=0 ; i < nLoops ; i++)
{
cout << endl << "Full Name of Student " << i <<": ";
cin.ignore();
cin.getline(pnStudents[i].chName,255);
pnStudents[i].nID=i;
}
In the first iteration of the loop, ignore() extracts a new line character that has been left in the stream by cin >> nLoops; call. istream::getline(), on the other hand, discards the trailing '\n' and so each subsequent iteration waits for and discards the first character of your input.
Move cin.ignore() just before the loop.
cin.ignore(); without an argument discards from cin, a stream of size 1.
istream& ignore ( streamsize n = 1, int delim = EOF );
Extract and
discard characters Extracts characters from the input sequence and
discards them.
Remove that. That seems to be the only thing in your code, which could eat one character away. Also, if you need to use ignore, use something like:
cin.ignore(256,' ');
^ ^ (number of char, delim)
If you are trying to ignore the character you took as input for nLoops, you need not do it in every iteration.
Related
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');
}
This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Using getline() in C++
(7 answers)
Closed 4 years ago.
Can anyone explain why I am having trouble with the below C++ code?
#include <iostream>
using namespace std;
class stud
{
public:
string name,adrs;
long long unsigned int mob;
};
int main()
{
stud s[10];
unsigned int num;
cout << endl << "Enter the number of students(<10): ";
cin >> num;
cout << endl;
for(int i = 0; i < num; i++)
{
cout << endl << "Enter student " << i+1 << " name(put '.' at end and press enter): ";
getline(cin, s[i].name); // this line skips some data before even they are
//entered and there is no error while compiling
}
system("CLS");
for(int i = 0; i < num; i++)
{
cout << endl << " Student " << i+1 << " name is: ";
cout << s[i].name << endl;
}
return 0;
}
When I try to input a string value for an object in the array as above, using getline() without any delimiter (which uses a new line by default), I don't get correct output since some other data is automatically being skipped.
But, when I use getline() as follows instead of above, it works fine, but it needs a delimiter at the end:
getline(cin, s[i].name, '.');
Please help me find a solution. I think the Enter key is pressed several times at one key press, and that's why the getline() skips some data. I'm not sure about this, though.
before correcting you program one thing to know is that
Actually, a newline is always appended to your input when you select Enter or Return when submitting from a terminal.
cin>> doesn't remove new lines from the buffer when the user presses Enter.
This has little to do with the input you provided yourself but rather with the default behaviour std::getline() exhibits. When you provided your input for the name (std::cin >> num;), you not only submitted the following characters, but also an implicit newline was appended to the stream, getline() mistakes this for user input along with enter.
It is recommended to use cin.ignore() to get rid of those extra characters after using cin>>(whatever) if you are going to use getline(cin,any string) later.
Edit this part of your code:
stud s[10];
unsigned int num;
cout << endl << "Enter the number of students(<10): ";
cin >> num;
cout << endl;
cin.ignore();//just add this line in your program after getting num value through cin
//fflush(stdin);
//cin.sync();
//getchar();
for(int i = 0; i < num; i++)
{
cout<<endl<< "Enter student " << i+1 << " name(put '.' at end and press enter): ";
getline(cin,s[i].name);
}
system("CLS");
you can use and may be tempted to use fflush(stdin) also but it is not recommended as it has undefined behaviour, as
According to the standard, fflush can only be used with output buffers, and obviously stdin isn't one.
about cin.sync():
using “cin.sync()” after the “cin” statement discards all that is left in buffer. Though “cin.sync()” does not work in all implementations (According to C++11 and above standards).
you can also use getchar() to get the newline caused by Enter
Consider the following code:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
class treasure
{
public:
char name[100];
double value[100];
double weight[100];
};
int itemNumber, totalWeight, i;
treasure item;
std::cout << "Enter total item weight: " << std::endl;
std::cin >> totalWeight;
std::cout << "Enter total item number: " << std::endl;
std::cin >> itemNumber;
for( i = 0; i < itemNumber; i++)
{
std::cout << "Enter item name: " << std::endl;
std::cin >> item.name[i];
}
return 0;
}
I wanted to input 5 item in the array but it is just asking for two item. It takes one item at first and then after printing three lines again takes another input. What seems to be the problem. What did went wrong?
char name[100]; means that you can save up to 100 items of type char, not 100 strings.
An important effect here is that your input is buffered. std::cin >> item.name[i]; takes one char from the input buffer and writes it to name[i]. The rest of your input remains in the buffer and will be used for the next execution of cin, i.e. the next execution of the same code line.
So if you enter e.g. 'abc' it saves 'a' to item.name[0], 'b' to item.name[1] and 'c' to item.name[2]. For item.name[3] the input buffer is empty so it waits for your next input.
i'm trying to make the c++ program that manage student list but got into error from the very beginning. Here's my program:
#include<iostream>
#include<string.h>
using namespace std;
struct Candidate
{
char id[5];
char fullname[30];
int reading, listening,total;
};
int main ()
{
struct Candidate can[100];
int n=0;
do {
cout << "Input number of candidate:";
cin >> n;
if (n <= 0 || n>=50)
cout << "Candidate number must be between 0 and 50:\n";
} while (n <= 0 || n>=50);
for (int i = 0; i < n; i++)
{
cout << "Input information for candidate number " << i + 1 << endl;
cin.ignore(32323, '\n');
cout << "Input ID(only 5 character):";
gets(can[i].id);
cout << "Input full name:";
gets(can[i].fullname);
do {
cout << "Input reading mark:";
cin >> can[i].reading;
if(can[i].reading < 5 || can[i].reading>495)
cout<<"Your reading mark is not between 5 and 495\n";
} while (can[i].reading < 5 || can[i].reading>495);
do {
cout << "Input listening mark:";
cin >> can[i].listening;
if(can[i].listening < 5 || can[i].listening>495)
cout<<"Your listening mark is not between 5 and 495\n";
} while (can[i].listening < 5 || can[i].listening>495);
can[i].total = can[i].reading + can[i].listening;
}
cout << endl << can[0].id<<endl;
}
So i got an output like this:
Input number of candidate:1
Input information for candidate number 1
Input ID(only 5 character):EW2RR
Input full name:Test1
Input reading mark:344
Input listening mark:233
EW2RRTest1
It seems like the value of fullname is written continually to ID. I have tried a lot of way to fix but couldn't figure out. Does anyone have a clue?
In every string if you have a string length of N you must have char array of size at least N+1 for '\0' which indicates that the string ends here for cout to stop printing.
In your case you declared char array of size 5 and you fill all 5 with characters so '\0' is put somewhere else. Notice that "id" and "fullname" locate next to each other , so my best guess is that gets put '\0' of when you scan "ID" which should be "id[5]" to "fullname[0]", and then when you scan "FULLNAME" , it replaces this '\0' , so "id" has no termination point and must use termination point of "fullname". That's why it seems like fullname has been appended to id. Be aware that this is not the default behavior , the program may act different on other machines.
Also , gets() is a broken function , if you use cin or scanf before , you should flush your stdin first by calling
fflush(stdin);
before you use gets() because sometimes '\n' is left in the stdin but in your case this was taken care by
cin.ignore(32323, '\n');
Using fgets() as Paul Rooney stated is much more preferable. I myself also had a lot of problems with gets.
Happy Coding!!
You need to put a terminal '\0' char at the end of every string.
When the ID gets printed, the code (cout) won't stop til it hits a NULL.
This is called overrunning your buffer.
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.