dynamic initalisations of c++ objects based on user input - c++

Hey sorry for the previous Question
OK..My project is to create and run a database for a college using c++
I have to use USN which is a Unique Student Number to access the database :
So i wrote the following program :
#include<iostream>
# include<conio.h>
#include<iomanip>
#include<string.h>
#include<stdlib.h>
int checkinarray(char[],char*);
using namespace std;
class student
{
private :
int sem;
float cgpa;
char password[11];
char passwordtrial[11];
void readdata();
void checkpassword();
void createpassword();
public :
char name[50];
int roll;
void printdata();
char USN[11];
static int number;
void opendatabase();
void firsttime();
public:
student(char n[50]="NONE")
{
number++;
roll=number;
cout<<endl<<"New record under the name of "<<n<<" has been created !"<<endl;
cout<<"Roll number set for new student as : "<<roll<<endl;
cout<<"Use this Roll number for further usage"<<endl<<endl;
};
};
void student::opendatabase()
{
int ch;
cout<<"Enter your name:"<<endl;
cin>>name;
cout<<"Enter your password"<<endl;
cin>>passwordtrial;
if(!strcmp(passwordtrial,password))
{
cout<<"Do you want to read or write";
cin>>ch;
switch(ch)
{
case 0 :
readdata();
break;
case 1 :
printdata();
break;
}
}
else
cout<<"Try Again";
};
void student::readdata()
{
cout <<endl<<"Enter the name of the student : ";
cin >> name;
cout <<endl<<"Enter the semester of the student : ";
cin >> sem;
cout <<endl<<" Enter the cgpa of the student : ";
cin >> cgpa;
};
void student :: printdata()
{
cout << "The name is : " << name << endl;
cout << "The sem is : " << sem << endl;
cout << "The roll is : " << roll << endl;
cout << "The cgpa is : " << cgpa << endl;
}
void student::firsttime()
{
cout<<"Enter your name :";
cin>>name;
cout<<"Hey "<<name<<" Welcome to DBMS "<<endl;
createpassword();
};
void student::createpassword()
{
cout<<"Please enter your 6 character password.. : ";
cin>>password;
cout<<"Please Input your Data here.... :" ;
readdata();
};
int student::number=0;
int main()
{
enum status {existing,newacc,exit};
enum functi{read,update};
char entry1[40];
char entry[10];
char usn[15];
char a[1000][15];
char n[40];
int i,j=0,k;
int s=2;
cout<<endl<<"WELCOME TO COLLEGE NAME"<<endl<<"Press enter to access Database...";
getch();
cout<<endl<<"Welcome to the Main Page of our Database : "<<endl;
while(1)
{//User option
cout<<endl<<"Do you want to access an old entry : "<<endl<<"OR"<<"Create a NEW entry : ";
cin>>entry1;
if(!strcmp(entry1,"old"))
s=existing;
else if(!strcmp(entry1,"new"))
s=newacc;
else
s=exit;
switch(s)
{
case existing:
{
i=1;
break;
}
case newacc:
{ i=1;
cout<<endl<<"Enter your usn : "<<endl;
cin>>usn;
strcpy(a[j],usn);
j++;
strcpy(n,usn);
cout<<n;
student usn(n);
usn.firsttime(); //Start here!! use i to go to next loop or stay in this loop,,change name entry to usn
break;
}
default :{cout<<"Error Input";i=0;break;}
}
if(i)
continue;
cout<<endl<<"What do u want to do??"<<endl<<"Read Entries "<<endl<<"Update entries";
cin>>entry;
if(!strcmp(entry,"read"))
s=read;
else if(!strcmp(entry,"update"))
s=update;
else
s=exit;
cout<<endl<<"Enter your usn : "<<endl;
cin>>usn;
if(checkinarray(a[15],usn))
{
switch(s)
{
case read:{
usn.printdata();
break;
}
case update:{
usn.firsttime();
break;
}
default :
cout<<"Are you sure you want to exit?"<<endl<<"Press 0 to exit"<<endl<<"to back to menu press 1";
cin>>k;
break;
}
if(!k)
break;
}
else cout<<"Invalid Roll number try again!";
}
}
int checkinarray(char a[][15],char b[])
{
int len;
//Finding the length of the string :
len=(sizeof(a)/sizeof(a[0]));
//Checking Conditions for roll number:
for(int k=0;k<len;k++)
{
if(strcmp(a[k],b))
return 1;//stringcompare!!
}
return 0;
}
okay so when i run this i get the following error :
request for member 'printdata' in 'usn', which is of non-class type 'char [15]'
AND
request for member 'firsttime' in 'usn', which is of non-class type 'char [15]'
So please help me overcome this error by suggesting different ways to create and call objects based on user input

OP's problem can be reduced to the following example:
#include<iostream>
#include<string.h>
using namespace std;
class student
{
public:
student(char n[50])
{
}
};
int main()
{
char usn[15];
char n[40];
{
cin >> usn;
strcpy(n, usn);
student usn(n);
}
usn.printdata();
}
This is what is meant by a Minimal, Complete, and Verifiable example. Not everything, but everything needed to reproduce the problem. The beauty of the MCVE is it has reduced the problem to the point where all of it can fit on the screen and probably within the brain, making it easy to analyze and test.
Things to note:
There are two variables named usn
char usn[15];
is an automatic variable within main. It is visible only within main and will expire at the end of main
student usn(n);
is an automatic variable within an anonymous block within main. It is visible only within this block and will expire at the end of the block.
Annotating this block to better explain what is happening, we get
{
cin >> usn; // uses char usn[15];
strcpy(n, usn);
student usn(n); // declares a new variable named usn that replaces char usn[15];for the remainder of this block
} // student usn(n); ends right here and is destroyed.
usn.printdata(); //uses char usn[15]; which has no printdata method.
So how do we fix this?
student usn(n); must have a wider scope.
one of these two variables must change names because once student usn(n); has wider scope it will collide with char usn[15];
Lets give that a quick try.
int main()
{
char usn[15];
char n[40];
student stud(n);
{
cin >> usn;
strcpy(n, usn);
}
stud.printdata();
}
Isn't possible because there is no data in n with which we can make stud. At least not for this minimal example.
int main()
{
char usn[15];
char n[40];
student * stud;
{
cin >> usn;
strcpy(n, usn);
stud = new student(n);
}
stud->printdata();
delete stud;
}
Solves that by dynamically allocating stud so that it is no longer scoped by the braces. Unfortunately that does pick up some extra memory management woes. stud must be deleted. Added a delete, but what if printdata throws an exception and delete stud; is skipped?
int main()
{
char usn[15];
char n[40];
std::unique_ptr<student> stud;
{
cin >> usn;
strcpy(n, usn);
stud.reset(new student(n));
}
stud->printdata();
}
std::unique_ptr takes care of that. But... What about that whole database thing? Why not store stud in a list?
int main()
{
char usn[15];
char n[40];
std::vector<student> studs;
{
cin >> usn;
strcpy(n, usn);
studs.emplace_back(n); // or studs.push_back(student(n));
}
for (student & stud: studs)
{
stud.printdata();
}
}
std::vector solves both problems at once.

Related

Difficulty in understanding c++ string literals

Here the below code is my some part of my program. It doesn't execute it says c++ forbids converting string constants to char*.How can I fix this error?
#include <cstring>
#include <iostream>
using namespace std;
class Bank
{
private:
char name[20];
int acc;
float amount;
public:
Bank()
{
strcpy("",name);
acc = 0;
amount = 0;
}
void open(int a)
{
cout << "Enter name:";
cin >> name;
acc = a;
cout << "Enter Amount" << endl;
cin >> amount;
}
void edit(int flag, float a);
};
int main()
{
Bank B[10];
}
std::strcpy("", name); needs to be std::strcpy(name, "");
Although, setting aside the fact that std::string would be a far better type for name (the future King of England, Charles Mountbatten-Windsor, would not be able to be a customer), writing
name[0] = 0;
would be sufficient.

Using erase for removing an element in an array of class objects

I want to remove a particular student object for a given roll no. from a students list using erase operation in STL. Following are my class designs.
But the compiler shows the following error message at place where I used the erase function.
no instance of overloaded function "std::vector<_Tp, _Alloc>::erase [with _Tp=Student, _Alloc=std::allocator<Student>]" matches the argument list -- argument types are: (Student) -- object type is: std::vector<Student, std::allocator<Student>>
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
class Student
{
int roll;
char *name;
int score;
public:
Student(int r=0)
{
roll=r;
}
void get_data()
{
cout<<"Enter roll : ";
cin>>roll;
cout<<"Enter name : ";
cin>>name;
cout<<"Score : ";
cin>>score;
}
void show_data()
{
cout<<"Roll : "<<roll<<endl;
cout<<"Name : "<<name<<endl;
cout<<"Score : "<<score<<endl;
}
int ret_score()
{
return score;
}
int ret_roll()
{
return roll;
}
};
class Student_array
{
public:
vector <Student> Student_array;
vector <Student>::iterator it;
void add_student()
{
Student s;
s.get_data();
Student_array.push_back(s);
}
void remove_student()
{
int roll;
cout<<"Enter roll no. of the student to be removed : ";
cin>>roll;
for(int i=0;i<Student_array.size();i++)
{
if(roll==Student_array[i].ret_roll())
{
Student_array.erase(Student_array[i]);
break;
}
}
cout<<"Roll no. not found enter a valid roll no.\n";
}
};
std::vector::erase() takes an iterator as input, not a Student object, eg:
void remove_student()
{
int roll;
cout << "Enter roll no. of the student to be removed : ";
cin >> roll;
for(int i = 0; i < Student_array.size(); ++i)
{
if (roll == Student_array[i].ret_roll())
{
Student_array.erase(Student_array.begin() + i);
return; // <-- not 'break'!
}
}
cout << "Roll no. not found enter a valid roll no.\n";
}
Alternatively, you can use std::find_if() to find the desired Student instead of using a manual loop, eg:
void remove_student()
{
int roll;
cout << "Enter roll no. of the student to be removed : ";
cin >> roll;
auto iter = std::find_if(Student_array.begin(), Student_array.end(),
[=](Student &s){ return s.ret_roll() == roll; }
);
if (iter != Student_array.end())
Student_array.erase(iter);
else
cout << "Roll no. not found enter a valid roll no.\n";
}
You must use iterator to erase an element
for (auto iter = Student_array.begin(); iter != Student_array.end(); ++iter)
{
if (roll != iter->ret_roll())
continue;
Student_array.erase(iter);
break;
}

Problem while reading objects from file in c++

I am doing a small college project where I have to add, edit and search records in/from file using OOP concept. Adding into file is working fine but whenever I try to read from file it is printing in unreadable texts.
Here is full code and output.
main.cpp
#include <iostream>
#include <cstdlib>
#include <fstream>
#define MIN 20
#define MAX 100
#include "student.h"
using namespace std;
void add_student();
void edit_student();
void search_student();
void addToFile(const Student&);
Student* fetchFromFile();
int getFileSize();
void updateFile(Student*);
// Student stud[MAX];
int main()
{
int choice;
system("cls");
system("Color B0");
while(1)
{
cout<<"\n\t\tWhat do you want to do?"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"\t\t1-Add student"<<endl;
cout<<"\t\t2-Edit student"<<endl;
cout<<"\t\t3-Search student"<<endl;
cout<<"\t\t4-Quit Program"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"Enter your choice: ";
cin>>choice;
switch(choice)
{
case 1:
add_student(); //calling add_student function to add records.
break;
case 2:
edit_student();
break;
case 3:
search_student();
break;
case 4:
return 0;
break;
default:
cout<<"Invalid choice";
break;
}
}
return 0;
}
int Student::id = getFileSize() - 1; //Initialize id equals to size of file
// setData function of class Student definition
void Student :: setData()
{
// taking input from user
cout<<"Enter student roll no in format(1XXX): ";
cin>>roll;
cout<<"Enter student name: ";
cin>>name;
cout<<"Enter stduent date of birth(dd/mm/yy): ";
cin>>dob;
cout<<"Enter stduent phone no: ";
cin>>phone;
cout<<"Enter student address: ";
cin>>address;
stdId = Student::id;
}
void Student :: showData()
{
cout<<stdId<<" ";
cout<<roll<<" ";
cout<<name<<" ";
cout<<dob<<"\t";
cout<<phone<<" ";
cout<<address<<"\n\n";
}
const int Student :: getRoll()
{
return roll;
}
Student& Student::operator = (const Student& newObj)
{
stdId = newObj.stdId;
roll = newObj.roll;
name = newObj.name;
dob = newObj.dob;
phone = newObj.phone;
address = newObj.address;
return *this;
}
void add_student()
{
Student stud;
Student::incrementId();
stud.setData();
addToFile(stud); //adding records to file
system("CLS");
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //getting records from file in array of objects
int length = getFileSize(); //getting length of array of objects
for(int i=0; i<(length-1); i++)
{
student[i].showData(); //showing all the data
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"You want to add more?(Y/n): ";
char c;
cin>>c;
if(c=='y' || c=='Y')
{
add_student();
}
else{
system("pause");
}
}
void edit_student(){
//Showing existing record first before editing
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student Existing record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //fetching all records from file
int length = getFileSize();
for(int i=0; i<(length-1); i++)
{
student[i].showData();
}
int idnumber;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"Which ID number your want to edit: ";
cin>>idnumber; //Asking the user at which ID he wants to make a change.
//checking for valid id number
if(idnumber>length || idnumber<0)
{
cout<<"\nInvalid ID Number."<<endl;
}
//showing existing information about that specific record
cout<<"\nExisted information about this record.\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"Father\tCell no. "<<"DOB "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
student[idnumber].showData();
cout<<"\n\nEnter new data for above shown record.\n\n";
student[idnumber].setData(); //Inputting data for that specific record.
updateFile(student);
cout<<"\n\nRecord updated successfully."<<endl;
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
for(int i=0; i<(length-1); i++) //Showing updated record Table
{
student[i].showData();
}
}
void search_student(){
Student* student = fetchFromFile();
int fileLenth = getFileSize() - 1;
int searchkey;
cout<<"Enter roll_no of student you want to search: ";
cin>>searchkey; //roll_no as the search key can be entered by user.
for(int i=1; i<fileLenth; i++)
{
if(searchkey==student[i].getRoll()) //checking for roll no
{
student[i].showData();
}
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
system("pause");
}
//FILE HANDLING
void addToFile(const Student& obj)
{
ofstream fout;
fout.open("records.txt", std::ofstream::app | std::ofstream::binary);
fout.write((char*)&obj, sizeof(obj));
cout<<"Added to file successfully!"<<endl;
fout.close();
}
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
returnObj[i] = obj;
i++;
}
fin.close();
delete[] returnObj;
return returnObj;
}
int getFileSize()
{
int i=0;
Student obj;
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
i++;
}
fin.close();
return i;
}
void updateFile(Student* student)
{
ofstream fout;
fout.open("records.txt", std::ofstream::binary);
fout.write((char*)&student, sizeof(student));
fout.close();
}
student.h header file
// A student class that hold students attributes like id, name, address and class
// Object of this class will be craeted to store student details
class Student
{
int stdId;
int roll;
std::string name;
std::string dob;
std::string phone;
std::string address;
public:
static int id; //we will increase 'id' whenever student is added to the record
//Member functions declaration
void setData(); //this function will take input from user and set the data to attributes of class
void showData(); //This function will give student data to user when called
static void incrementId()
{
id++;
}
const int getRoll();
Student& operator = (const Student&);
};
Sample output 1
When I add a student object to file
Sample output 2
Reading all records from file
Problem1: Showing garbage value of id.
Sample output 3
Adding another object to file
Sample output 4
Reading all objects from file
Sample output 5
Now went back and chose to edit record
Problem2: See how the records are printing in unreadable form.
Why is this happening. Now if I close program and run it again then it is still showing in unreadable text.
Hope you get my issue. I want to have detailed explanation about this. Also, if I have done other miscellaneous mistakes, please let me know.
Thank you!
Student is too complicated to read with unformatted IO like read and write. In technical terms, it is not Trivially Copyable because it contain std::strings, and string is not Trivially Copyable.
The easiest thing to do is to abandon read and write. Most of your data is string data, so write << and >> overloads for Student and store everything as text.
friend std::ostream & operator<<(std::ostream & out,
const Student & stu)
{
out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n';
return out;
}
Reading the data back in is a bit trickier
friend std::istream & operator>>(std::istream & in,
Student & stu)
{
std::string line;
if (std::getline(in, line))
{
std::stringstream strm(line);
if (!(strm >> stu.stdId >> comma >> stu.roll >> comma) ||
!std::getline(strm, stu.name, ',') ||
!std::getline(strm, stu.dob, ',') ||
...))
{ // If any read failed, mark the stream as failed so the caller knows.
out.setstate(std::ios_base::failbit);
}
}
return out;
}
First, a minor trick, add a empty constructor for class to initailial all members, integers{0}, and string{}, which will elminiate some unwanted gabages.
Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}
Your major problem arised from the function fetchfomrfile() where you delete the fetched Student array, therefore the caller received a undefined data array:
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
//reading records from file
fin.close();
delete[] returnObj;// <<<< youe deleted
return returnObj; // and return it as undefined
}
Since you are able to calculate the size of file, I suggest in the caller function:
void search_student(){
// Student* student = fetchFromFile();
Student *student = new Stduent [getFileSize()];
fecchFromFile(student); // use this array in fetch_file
// other things
}
Rewrite fetchFromFile as :
viod fetchFromFile(Stduent *ss)
{
// read file data to array ss[i];
}

Why is the syntax for taking the input about name not working?

#include<iostream>
#include<string>
using namespace std;
class data{
string name;
string code;
public :
void getname()
{
cout<<"Enter name : ";
getline(cin,name);
}
void getcode()
{
cout<<"Enter code : ";
getline(cin,code);
}
void display()
{
cout<<"Name : "<<name;
cout<<"Code : "<<code;
}
};
int main()
{
int n,i=0; cin>>n;
data stud[n];
while(i<n)
{
stud[i].getname();
stud[i].getcode();
i++;
}
for(int i=0;i<n;i++)
stud[i].display();
return 0;
}
In Line 13: The getline() is not executed. Can anyone explain its cause and an alternative?
Initially, I thought that I may have missed a header file or the syntax is wrong, but that is not the case as the syntax for input of code works just fine.
When using cin and getline function alternatively, you should clear the cin input stream. by using cin.ignore() funtion.
Here I am using cin.ignore() after your cin statements because you want to ignore the "\n" left in the buffer after taking your int variable with cin.
#include<iostream>
#include<string>
using namespace std;
class data{
string name;
string code;
public :
void getname()
{
cout<<"Enter name : ";
getline(cin,name);
}
void getcode()
{
cout<<"Enter code : ";
getline(cin,code);
}
void display()
{
cout<<"Name : "<<name;
cout<<"Code : "<<code;
}
};
int main()
{
int n,i=0;
cin>>n;
cin.ignore();
data stud[n];
while(i<n)
{
stud[i].getname();
stud[i].getcode();
i++;
}
for(int i=0;i<n;i++)
stud[i].display();
return 0;
}
Hope This Might Helps: )
For starters there is a typo in this function
void getname()
{
cout<<"Enter name : ";
getline(cin,code);
^^^^
}
And this declaration of the array
int n,i=0; cin>>n;
data stud[n];
is invalid. The variable n is not initialized and variable length arrays is not a standard C++ geature.

reading/writing class objects to files in c++

#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
class Student{
private:
char name[40];
char grade;
float marks;
public:
void getdata();
void display();
};
void Student::getdata(){
char ch;
cin.get(ch);
cout<<"Enter name : ";
cin.getline(name,40);
cout<<"Enter grade : ";
cin>>grade;
cout<<"Enter marks : ";
cin>>marks;
cout<<"\n";
}
void Student::display(){
cout<<"Name : "<<name<<"\t";
cout<<"Grade : "<<grade<<"\t";
cout<<"Marks : "<<marks<<"\t"<<"\n";
}
int main(){
system("cls");
Student arts[3];
fstream f;
f.open("stu.txt",ios::in|ios::out|ios::binary);
if(!f){
cerr<<"Cannot open file !";
return 1;
}
for(int i=0;i<3;i++){
arts[i].getdata();
f.write((char*)&arts[i],sizeof(arts[i]));
}
f.seekg(0); //The question is about this statement;
cout<<"The contents of stu.txt are shown below : \n";
for(int j=0;j<3;j++){
f.read((char*)&arts[j],sizeof(arts[j]));
arts[j].display();
}
f.close();
return 0;
}
The above program reads and writes objects of Student from/to the file "stu.txt".
It runs fine. But it runs fine even if I switch off the fin.seekg(0) statement. I don't understand this part ? Are we not supposed to set the file pointer to the beginning of the file - before starting to read objects from the file(in the context of this particular program)?.
If you are at the end of the file, the read method call will fail, thus the Student structures are left untouched (so you are just printing again the same structures which you left untouched after writing them to file).