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
Related
I have written a simple program in two ways. The program is for getting data from a user, storing it in a txt file, retrieving the data and displaying it. The problem is that one approach works while the other does not. I dont understand why.
The one that works is this:
#include <iostream>
#include <fstream>
using namespace std;
class customer{
public:
// Declaring member variables and functions
string name, address, telNo;
int age;
void createCustomer();
void displayInfo(string inputName);
};
// Member function of customer to enter new customer details
void customer::createCustomer(){
customer c;
ofstream file;
file.open("customers.txt", ios::out);
cout << "Enter Name: ";
cin >> c.name;
cout << "Enter Age: ";
cin >> c.age;
cout << "Enter Address: ";
cin >> c.address;
cout << "Enter Telephone Number: ";
cin >> c.telNo;
file.write((char*)&c, sizeof(c));
file.close();
cout << "\n";
}
// Member function of customer to display customer information
void customer::displayInfo(string inputName){
customer c;
ifstream file;
file.open("customers.txt", ios::in);
if(!file){
cout << "Could Not Open customers.txt File\n";
return;
}
while(!file.eof()){
file.read((char*)&c, sizeof(c));
if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
}
}
file.close();
}
int main(){
customer c;
c.createCustomer();
c.displayInfo("name");
return 0;
}
It gives the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
Name-------------> name
Age--------------> 21
Telephone Number-> telno
Address----------> add
The one that doesnt work is this:
#include <iostream>
#include <fstream>
using namespace std;
class customer{
public:
// Declaring member variables and functions
string name, address, telNo;
int age;
void createCustomer();
void displayInfo();
};
// Member function of customer to enter new customer details
void customer::createCustomer(){
customer c;
ofstream file;
file.open("customers.txt", ios::out);
cout << "Enter Name: ";
cin >> c.name;
cout << "Enter Age: ";
cin >> c.age;
cout << "Enter Address: ";
cin >> c.address;
cout << "Enter Telephone Number: ";
cin >> c.telNo;
file.write((char*)&c, sizeof(c));
file.close();
cout << "\n";
}
// Member function of customer to display customer information
void customer::displayInfo(){
string inputName = "name";
customer c;
ifstream file;
file.open("customers.txt", ios::in);
if(!file){
cout << "Could Not Open customers.txt File\n";
return;
}
while(!file.eof()){
file.read((char*)&c, sizeof(c));
if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
}
}
file.close();
}
int main(){
customer c;
c.createCustomer();
c.displayInfo();
return 0;
}
All I have done is put the string inputName variable inside the function instead of passing it as an argument.
It gives only the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
If I remove the if condition:
while(!file.eof()){
file.read((char*)&c, sizeof(c));
//if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
//}
}
i get the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
Name-------------> 0∙⌂┼
Age--------------> 21
Telephone Number-> name
Address----------> §
Why are the name and address fields outputting random symbols and the telephone number field outputting value of the name field?
Neither program is correct. It's an error use read on a type like customer because it contains sub-objects that need constructing, namely the string members name, address and telNo. Calling read does not call any constructor for the objects you are reading and so this is invalid.
Since read does not work for strings it doesn't make any sense to use write on a class containing a string either because you won't be able to read back what you have written.
If you want to write a customer to a file you can do it something like this
file << c.name << ' ' << c.age << ' ' << c.telNo << ' ' << c.address << '\n';
and then something similar for reading (although you then you would have to be careful of any spaces in your data).
In my program, I'm having an issue with one function trying to put three different types into an array. Is that possible, or do I have to work around this? I need them in one vector so I can recall that array in another function to delete it.
void addStudent()
{
string major;
double gpa;
unsigned seed = time(0);
srand(seed);
int rand_ID = rand() % 9000 + 1000;
cout << "Please enter major" << endl;
cin >> major;
cout << "Please enter GPA" << endl;
cin >> gpa;
cout << "------Add Student------" << endl;
cout << "ID: " << rand_ID << endl;
cout << "Major: " << major << endl;
cout << "GPA: " << gpa << endl;
ofstream students;
students.open("students.txt", ios_base::app);
students << rand_ID << " " << major << " " << gpa << endl; // I want to turn this into an array that I can send to the file students
}
It sounds like you want to put different students in a vector; and those students will be represented by a struct containing an int ID, string major and double GPA.
struct Student {
int id;
std::string major;
double gpa;
};
std::vector<Student> students;
Basically trying to just run this program for extra learning, Xcode won't understand that I have written a class, and wont implement it. Really confused and need some guidance.
When I run the code only the main method is implemented, nothing else works...
#include <iostream>
using namespace std;
class students {
int id;
char name[20];
int s1;
int s2;
int s3;
public:
void getData() {
cout << "Enter the ID " << endl;
cin >> id;
cout << "Enter the name " << endl;
cin >> name;
cout << "Enter the grade in subject 1 " << endl;
cin >> s1;
cout << "Enter the grade in subject 2 " << endl;
cin >> s2;
cout << "Enter the grade in subject 3 " << endl;
cin >> s3;
}
void putData() {
cout << id << " " << name << " " << s1 << " " << s2 << " " << s3 << endl;
}
};
int main () {
students s[20];
int i, n; //i is for the for loop, n for number of students
cout << "Enter the number of students " << endl;
cin >> n;
for (i=0;i>n;i++)
{
s[i].getData();
}
for (i=0;i>n;i++)
{
s[i].putData();
}
return 0;
}
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.
This question already has answers here:
Using getline(cin, s) after cin [duplicate]
(13 answers)
Closed 5 years ago.
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
void cpp_string();
void cstyle_string();
int main()
{
cpp_string();
cstyle_string();
system("pause");
return 0;
}
void cpp_string()
{
string fName, lName;
char grade;
int age;
cout << "What is your first name?";
getline(cin, fName);
cout << "What is your last name?";
getline(cin, lName);
cout << "What letter grade do you deserve?";
cin >> grade;
cout << "What is your age?";
cin >> age;
cout << "Name: " << fName << ", " << lName << endl;
cout << "Grade: " << grade << endl;
cout << "Age: " << age << endl;
return;
}
void cstyle_string()
{
char fNm[20], lNm[20];
char grade;
int age;
cout << "What is your first name?";
cin.get(fNm, 20).get();
cin.clear();
cout << "What is your last name?";
cin.get(lNm, 20).get();
cout << "What letter grade do you deserve?";
cin >> grade;
cout << "What is your age?";
cin >> age;
cout << "Name: " << fNm << ", " << lNm << endl;
cout << "Grade: " << grade << endl;
cout << "Age: " << age << endl;
return;
}
I'm getting output as
What is your first name?demiurge conon
What is your last name?no
What letter grade do you deserve?a
What is your age?22
Name: demiurge conon, no
Grade: a
Age: 22
What is your first name?What is your last name?What letter grade do you deserve?What is your age?Name: ,
Grade: ╠
Age: -858993460
Press any key to continue . . .
but if I run cstyle_string() in different file then I'm not getting any errors code works perfectly.
I want to know why this is happening?
There are two question.
Redundant \n
the state of cin
The last cin in cpp_string is cin >> age.
It will leave a \n not extracted.
In first of cstyle_string is cin.get(fNm, 20).get();
The delimiting character is not extracted from the input sequence if found, and remains there as the next character to be extracted from the stream
the cin.get(FNm, 20) will parse empty input before \n, and no characters are available in the stream in actually. In this case, the failbit flag will be set and next all cin >> operator will fail.
You can only call cstyle_string and press enter directly, the same thing will happen.