Character dispaying - c++

I know this maybe such a wierd question but it stucks me for a couple of days ago. My assignemnt is to display the students' information and update them using STRUCT type. Here is my works:
#include <iostream>
using namespace std;
struct DATE
{
int day;
int month;
int year;
};
struct STUDENT{
char ID[8];
char name[50];
DATE birthday;
char address[100];
float Math;
float English;
float CS;
};
void inputClass(STUDENT* &list, int &n)
{
cout << "Please enter the number of students: ";
cin >> n;
list = new STUDENT[n+1];
for(int i=1; i<=n; i++)
{
cout << "Please enter the info of student " << i << endl;
cout << "ID: ";
cin >> (&list[i]) -> ID; //the same with "list[i].ID"
fflush(stdin);
cout << "Name: ";
cin >> (&list[i]) -> name;
fflush(stdin);
cout << "Date of Birth\n";
cout << "Day: ";
cin >> (&list[i]) -> birthday.day;
fflush(stdin);
cout << "Month: ";
cin >> (&list[i]) -> birthday.month;
fflush(stdin);
cout << "Year: ";
cin >> (&list[i]) -> birthday.year;
fflush(stdin);
cout << "Address: ";
cin >> (&list[i]) -> address;
fflush(stdin);
cout << "Math result: ";
cin >> (&list[i]) -> Math;
fflush(stdin);
cout << "English result: ";
cin >> (&list[i]) -> English;
fflush(stdin);
cout << "CS result: ";
cin >> (&list[i]) -> CS;
fflush(stdin);
cout << "************* Next Student *************\n" ;
}
}
void updateScore(STUDENT* list, int n)
{
cout << "Who do you want to update?" << endl;
cout << "Ordinal Number(s): ";
cin >> n;
//Display outdated results
cout << "Student's Name: " << (&list[n])-> name << endl;
cout << "*********** Current Results ***********" << endl;
cout << "Math: " << (&list[n]) -> Math << endl;
cout << "English: " << (&list[n]) -> English << endl;
cout << "CS: " << (&list[n]) -> CS << endl;
//Update results
cout << "Please update the results" << endl;
cout << "Math result: ";
cin >> (&list[n]) -> Math;
fflush(stdin);
cout << "English result: ";
cin >> (&list[n]) -> English;
fflush(stdin);
cout << "CS result: ";
cin >> (&list[]) -> CS;
fflush(stdin);
}
void main()
{
STUDENT* list;
int n;
inputClass(list, n);
updateScore(list, n);
}
In the "//Display outdated result" section, I used "cout" to print out the Name of the regarding student based on his/her ordinal numbers. However, let's say I want to get the whole name like: "John Smith". What I have got, however, is only "John". Is there a way I can get all of the characters?
Many thanks for your help and sorry for my bad English, I am a student from Vietnam.

Use std::getline from the <string> header, with a std::string variable, instead of >> and raw character array.
The >> reads whitespace-separated words of input.
The raw character array doesn't adjust to the needed length, and you risk Undefined Behavior on buffer overflow.
In passing, many/most programmers find all UPPERCASE to be an eyesore; it hurts the eyes.
Also, all uppercase is by convention (in C and C++) reserved for macro names.

As it's already been answered previously, you should use std::getline (refer to this question).
I'm assuming you're using a IDE, and it usually fixes a lot of things for us, users, but this may turn your code non-compilable in other compilers, so there are some things you should fix to be able to compile your code everywhere:
Always pay attention if you're adding the necessary includes. There's lack of an include statement for stdin and fflush. You should add:
#include <cstdio>
Also, main should return an int, so, it should have been something like
int main(int argc, char* argv[]){ /*Although you can usually omit the parameters*/
// Code
return 0;
}
By the way, just as a side comment, you forgot the subscript at:
cout << "CS result: ";
cin >> (&list[]) -> CS;

Related

Use of getline to read a string with white spaces in a structure

I want to read strings with white spaces into members of a structure. Tried using getline but both the output statements are clubbed with a single cin for both. As per the similar posts here, tried using cin.ignore, but the input is not read into the member of the structure. Pls help. It's a part of my assignment and I'm a beginner in C++. This is how my code looks like:
#include <string.h>
using namespace std;
struct book {
string title, author;
int no_of_pages, year;
float price;
};
int main() {
int N;
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
book b[N];
int x;
for (x = 0; x < N; x++) {
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
// cin.ignore();
cin.ignore(1000, '\n');
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
}
for (x = 0; x < N; x++) {
cout << "\n\n";
cout << "The details of book" << x + 1 << " are:" << endl;
cout << "Title :" << b[x].title << endl;
cout << "Author :" << b[x].author << endl;
cout << "No. of pages :" << b[x].no_of_pages << endl;
cout << "Price :" << b[x].price << endl;
cout << "Publishing year:" << b[x].year << endl;
cout << "---------------------------------------------";
}
return 0;
}
There's no point in using cin.ignore() in between two calls to getline. ignore is used to discard remaining characters after numeric input. So the place to use it is after numeric input and before the next getline. Like this
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
cin.ignore(1000, '\n');
That said I would just read everything using getline, then convert the strings to numbers where needed. That's simpler and cleaner, all you need to know is how to convert a string to an integer, which you can easily research for yourself.
There are two places you should put cin.ignore in your code:
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
// First cin.ignore here
cin.ignore(1000, '\n');
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
// Second cin.ignore here
cin.ignore(1000, '\n');
Besides this I see two more problems in your code:
#include <string> not <string.h>
add #include <iostream>
Why cin.ignore is necessary? User is expected to provide new line ('\n') delimited input. When getline is used, it leaves the input stream in such a state that the next attempt to read input from stream will start at next line. This is not true for operator >>. What int x; cin >> x; does here is it reads only the integer not the new line character present right after the integer. Hence, the next attempt to read will continue within the same line. getline will then find no character before new line and hence will fetch an empty string. To avoid this and to effectively start reading from the next line, cin.ignore is necessary.

How to create a function to read/write data to struct members?

I'm trying to create a program that read and print students' data with c++. for that, I've created a struct Student, a function to read data from the user and assign it to a struct instance s1 and a function to print students' data on the screen, and I think the problem is with the function that read/write data.
Here is the my code:
#include<iostream>
#include<string>
using namespace std;
struct Student
{
char name[30];
int age;
double gpa;
string department;
};
Student read_data(Student x)
{
cout << "Name (30 characters maximum): ";
cin.get(x.name, 30);
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
return x;
}
void print_data(Student x)
{
cout <<
"\n***************************************************************" << endl;
cout << "Name: " << x.name << endl;
cout << "Age: " << x.age << endl;
cout << "Department: " << x.department << endl;
cout << "GPA: " << x.gpa << endl;
}
int main()
{
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
print_data(read_data(s1));
system("pause");
return 0;
}
The output of this code is:
This program stores data of three students
Enter 1st student's data
Name (30 characters maximum): Ahmed Maysara
Age: 22
Department: CS
GPA: 3.5
Name (30 characters maximum): Age: Department: GPA:
***************************************************************
Name:
Age: -858993460
Department:
GPA: -9.25596e+61
Press any key to continue . . .
As you see, the output is out of my expectations :) ..
Any help ?!
Both CinCout and David are correct.
There are a couple of problems with your code as it now stands.
The first problem is that while you successfully call the function read_data(s1), s1 is a just a copy. So, when the function sets all of the values for the student using cin, it is really just setting a copy's values. You can either make it so that you are passing in the original, or you can return the student (which you are doing) and set s1 equal to the result (which you are not).
To make sure that you pass in the original, you can go to where you declared read_data. Instead of saying Student read_data(Student x), you should place an ampersand after the parameter that you don't want to copy Student read_data(Student &x). This is called passing by reference (you reference the original instead of referencing by copy)
Alternatively, you could con just set s1 to the result where you call it in main. You could say s1 = read_data(s1); and that would work fine, though a bit more inefficiently.
Lastly, the other glaring error in the code is that you accidentally call read_data again when you say print_data(read_data(s1)). Instead, say print_data(s1).
Instead of passing and returning the structure object each time on call of read_data and print_data we could add those inside the structure itself, We could create object of Student and call the functions read and print within the same.
struct Student
{
char name[30];
int age;
double gpa;
string department;
Student(): age(0), gpa(0)
{
memset( name, 0, 30 );
}
void read()
{
cout << "\nName (30 characters maximum): ";
cin.get(name, 30);
cout << "\nAge: ";
cin >> age;
cout << "\nDepartment: ";
cin >> department;
cout << "\nGPA: ";
cin >> gpa;
}
void print()
{
cout << "\n***************************************************************" << endl;
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Department: " << department << endl;
cout << "GPA: " << gpa << endl;
}
};
int main()
{
Student s1;
s1.read();
s1.print();
return 0;
}
You are passing copy of s1 into the read_data function, but not bothering to update the value based on the return arg. i.e. something like this should work.
s1 = read_data(s1);
print_data(s1);
Alternatively, pass by reference instead of value:
void read_data(Student& x)
{
cout << "Name (29 characters maximum): "; // requires null terminator
cin >> x.name; // just read into the buffer directly
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
}
And then later:
read_data(s1);
print_data(s1);
change you read_data with something like this
void read_data(Student& x)
{
cout << "Name (30 characters maximum): ";
///cin.get(x.name, 30);
cin.getline(x.name, 30);
cout << "Age: ";
cin >> x.age;
cin.ignore();
cout << "Department: ";
std::getline(cin, x.department);
///cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
cin.ignore();
// return x; can't return a value from a void function
}
and in main function or where you are calling the read_data function use
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
read_data(s2);
read_data(s3);
the reason you are getting weird values in return is that you capture buffer with cin >> instead getline
see
description of getline function
description of cin.ignore function

c++ why is there still input buffer left?

After my first entry, my second entery name field fills up with the input buffer from the previous entry. Why? I am even using the getline but the problem still persists. Please help me with the problem. This is question from Jumping Into C++ book .
#include <iostream>
#include <string>
using namespace std;
struct Person
{
string name;
string address;
long long int PhoneNumber;
};
void displayEntries(Person p[])
{
int enteryNumber;
cout << "Enter the entry number of the person for details(enter 0 to display all entries): ";
cin >> enteryNumber;
if(enteryNumber == 0)
{
for(int i = 0; i < 10; i++)
{
cout << "Entery Number: " << i + 1;
cout << "Name: " << p[i].name << endl;
cout << "Address: " << p[i].address << endl;
cout << "Phone Number: " << p[i].PhoneNumber << endl;
}
}
do
{
cout << "Entery Number: " << enteryNumber;
cout << "Name: " << p[enteryNumber].name << endl;
cout << "Address: " << p[enteryNumber].address << endl;
cout << "Phone Number: " << p[enteryNumber].PhoneNumber << endl;
} while (enteryNumber != 0);
}
int main()
{
Person p[10];
for(int i = 0; i < 10; i++)
{
cout << "Enter the details of the person\n\n";
cout << "Name: ";
getline(cin, p[i].name);
cout << "Address: ";
getline(cin, p[i].address);
cout << "Phone Number: ";
cin >> p[i].PhoneNumber;
cout << endl;
}
displayEntries(p);
return 0;
}
You can see what is happening when you read the reference for getline:
When used immediately after whitespace-delimited input, e.g. after
int n;
std::cin >> n;
getline(cin, n); //if used here
getline consumes the endline character left on the input stream by operator>>, and returns immediately. A common solution is to ignore all leftover characters on the line of input with
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
before switching to line-oriented input.
cin >> p[i].PhoneNumber; only gets the number. That leaves the line ending still in the input buffer to be read the next time you try to read a line.

Using a struct to hold information entered by the user C++

Okay, so I am writing a C++ program to declare a struct data type that holds the following information on an employee (First Name, Last Name, ID, Pay Rate, and Hours). My problem is that the user can only enter in the ID and First Name, then the whole program runs without letting the user enter the rest of the data.
Heres my code:
#include <iostream>
#include <iomanip>
using namespace std;
struct Employee
{
int employeeID;
char firstName;
char lastName;
float payRate;
int hours;
};
int main()
{
int i, j;
cout << "How Many Employees Do You Wish To Enter?:\n\n";
cin >> j;
Employee info;
for (i = 0; i < j; i++)
{
cout << "Enter in the Data for Employee number " << i + 1 << endl;
cout << setw(5) << "\n Please Enter The Employee ID Number: ";
cin >> info.employeeID;
cout << setw(5) << "\n Please Enter Employees First Name: ";
cin >> info.firstName;
cout << setw(5) << "\n Please Enter Employees Last Name: ";
cin >> info.lastName;
cout << setw(5) << "\n Please Enter Employees Pay Rate: ";
cin >> info.payRate;
cout << setw(5) << "\n Please Enter The Hours The Employee Worked:
";
cin >> info.hours;
}
cout << "\n\n \n";
cout << "ID" << setw(15) << "First Name" << setw(10) << "Last Name" <<
setw(10) << "Pay Rate" << setw(10) << "Hours";
cout << endl;
for (i = 0; i < j; i++)
{
cout << "\n" << info.employeeID << setw(15) << info.firstName << setw(10) << info.lastName << setw(10) << info.payRate << setw(10) << info.hours;
}
cout << "\n\n \n";
system("pause");
return 0;
};
#include <iostream>
#include <iomanip>
#include <string> //Allows you to use strings, which are way more handy for text manipulation
#include <vector> //Allows you to use vector which are meant to be rezied dynamicaly, which is your case
using namespace std;
struct Employee
{
int employeeID;
string firstName; //HERE : use string instead of char (string are array of char)
string lastName; //HERE : use string instead of char
float payRate;
int hours;
};
int main()
{
int j;
cout << "How Many Employees Do You Wish To Enter?:\n\n";
cin >> j;
vector<struct Employee> info; //creation of the vector (dynamic array) to store the employee info the user is going to give you
for (int i = 0; i < j; i++) //declare your looping iterator "i" here, you will avoid many error
{
struct Employee employee_i; // create an employee at each iteration to associate the current info
cout << "Enter in the Data for Employee number " << i + 1 << endl;
cout << "\n Please Enter The Employee ID Number: ";
cin >> employee_i.employeeID;
cout << "\n Please Enter Employees First Name: ";
cin >> employee_i.firstName;
cout << "\n Please Enter Employees Last Name: ";
cin >> employee_i.lastName;
cout << "\n Please Enter Employees Pay Rate: ";
cin >> employee_i.payRate;
cout << "\n Please Enter The Hours The Employee Worked: ";
cin >> employee_i.hours;
info.push_back(employee_i); //store that employee info into your vector. Push_back() methods expands the vector size by 1 each time, to be able to put your item in it
} // because you employee variable was create IN the loop, he will be destruct here, but not the vector which was created outside
cout << "\n\n \n";
for (int i = 0; i < j; i++) //the loop to get back all the info from the vector
{
cout << "ID :" << info[i].employeeID << " First Name :" << info[i].firstName << " Last Name :" <<
info[i].lastName << " Pay Rate :" << info[i].payRate << " Hours :"<< info[i].hours;
cout << endl;
//notice the info[i], which leads you to the employee you need and the ".hours" which leads to the hours info of that specific employee
}
system("pause");
return 0;
}
First, please read Tips and tricks for using C++ I/O (input/output). It might be helpful to understand C++ I/O.
Here are some comments on your code:
First
Use string instead of char.
struct Employee
{
int employeeID;
string firstName;
string lastName;
float payRate;
int hours;
};
Second
Use array of Employee object to store multiple employees.
Employee info[100];
Third
Use cin carefully depending data types. In your case, it would be something like this:
cout << "Enter in the Data for Employee number " << i + 1 << endl;
cout << setw(5) << "\n Please Enter The Employee ID Number: ";
cin >> info[i].employeeID;
cin.ignore(); //It is placed to ignore new line character.
cout << setw(5) << "\n Please Enter Employees First Name: ";
getline (cin, info[i].firstName);
cout << setw(5) << "\n Please Enter Employees Last Name: ";
getline (cin, info[i].lastName);
cout << setw(5) << "\n Please Enter Employees Pay Rate: ";
cin >> info[i].payRate;
cout << setw(5) << "\n Please Enter The Hours The Employee Worked: ";
cin >> info[i].hours;
Fourth
std::getline() can run into problems when used before std::cin >> var. So, std::cin.ignore() can be used in this case to solve the problem.
I hope it helps.

reading and printing inputs and C-string in C++

I have a simple program to read and echoed the user's input and calculate the total amount. I'm having trouble with arrays. I want to know how to use an array to read and print each product name and the cost and the find grand total upon checkout. Should I also use functions?
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
const int MAX_CHAR = 100;
void pause();
int main()
{
char productName[MAX_CHAR];
double price;
char reply;
double total = 0;
cout << fixed << showpoint << setprecision(2);
cout << "Welcome to your shopping calculator!" << endl;
do {
cout << "Enter the product name: ";
cin.get(productName, MAX_CHAR, '\n');
cin.ignore(100, '\n');
cout << "Enter the amount: $";
cin >> price;
while (!cin) {
cin.clear();
cin.ignore(100, '\n');
cout << "Invalid amount. Please enter the amount: $";
cin >> price;
}
cin.ignore(100, '\n');
cout << "The product name is" << " " << productName << " "
<< " and it costs" << " " << "$" << price << endl;
total += price;
cout << "The total amount is " << " " << total << endl; //program needs to keep a running total
cout << "Would you like to continue shopping? (y/n): ";
cin >> reply;
cin.ignore(100, '\n');
} while ( reply == 'Y' || reply == 'y'); //the program will continue until the user wants to checkout
pause();
return 0;
}
void pause()
{
char ch;
cout << "Press q followed by Enter key to continue....." << endl;
cin >> ch;
}
Thanks for the help!
You need to map the product name to the cost using std::map so that you can print the respective pairs afterwards. As for the grand total, that's stored in the variable total so printing it is trivial.
To do this, you will need to include the <map> header, as the Standard Library class std::map is defined there. Moreover, I've also included some changes to your code that should be considered. In particular, using std::string and using std::numeric_limits<...>::max() to return the constant.
#include <iostream>
#include <string>
#include <map>
int main()
{
std::string productName;
double price;
char reply;
double total = 0;
std::map<std::string, double> productToPrice;
std::cout << std::fixed << std::showpoint << std::setprecision(2);
std::cout << "Welcome to your shopping calculator!" << std::endl;
while ((std::cin >> reply) && (reply == 'y' || reply == 'Y'))
{
cout << "Enter the product name: ";
std::cin >> productName;
cout << "Enter the amount: $";
while (!(cin >> price))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Invalid amount. Please enter the amount: $";
}
total += price;
productToPrice.insert(std::make_pair(productName, price));
cout << "Would you like to continue shopping? (y/n): ";
}
...
}
Note the changes I made. Please use them.
To print you simply do:
typedef std::map<std::string, double>::const_iterator iter_type;
for (iter_type beg(productToPrice.begin()),
end(productToPrice.end()); beg != end; ++beg)
{
std::cout << beg.first << " -- " << beg.second << std::endl;
}
std::cout << "\nThe total price is: " << total;
You are definitely on the right track. I think you are mixing I/O conventions in C and C++ which is causing a lot of your issues. It would be very helpful if you could elaborate on what exactly your issues are.
Carpetfizz is correct in that since you don't know the number of items at compile time, you will need to use a dynamic array with std::vector. You can learn about vectors here.
In addition, C++ has a very useful string data type that you can include with #include <string>. Using this, as well as a junk string such as string junk;, you can avoid using cin.ignore(...) and get cleaner I/O by using getline(cin, junk).
I strongly recommend doing this because creating a vector of C-strings or C-style strings is a pain, because C-style strings are actually arrays of characters, so you'd have to use std::vector<std::vector<char> > products.