Currently I'm trying to set up a member function for Student that reads a string from cin, is used as an argument for this function and then creates a Student object with the data. However, is it giving me a bad_alloc error. I know the function is getting the string but it gives this error after the new object is created.
Error:
./a.out
Please insert name for student:
Bob_Russel
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
Constructor:
Student::Student(string tname){
name = tname;
}
Function:
Student Student::readStudent(istream &i){
Student *stud;
string y;
i >> y;
stud = new Student(y);
return *stud;
}
testStudent.cpp:
#include "Student.h"
int main(){
Student *stud3;
cout << "\nPlease insert name for student:\n";
stud3->readStudent(cin);
return 0;
}
Not only does the code leak memory (creating a new Student in readStudent that is never deleted), in main you are using an uninitialized pointer to call readStudent. Possibly this is corrupting your heap such that the call to new throws a std::bad_alloc.
Take another look at C++ memory management and object lifetimes. There is really no need to use pointers at all here. As a starting point, your main could be modified to this:
int main() {
Student stud3;
std::cout << "Please insert name for student:" << std::endl;
stud3.readStudent(std::cin);
}
It would perhaps also be better if you read in the name within main (as a std::string), and then pass the name directly to the Student constructor:
int main() {
std::cout << "Please insert name for student:" << std::endl;
// Read in the name.
std::string name;
std::cin >> name;
// Create the student with the input name.
Student stud3(name);
}
It looks like you're trying to implement a factory method. If that's the case, then you're missing the static keyword and the correct syntax for the readStudent call.
class Student{
public:
Student(std::string tname);
static Student* readStudent(std::istream &i);
private:
std::string name
};
Student::Student(std::string tname) {
name = tname;
}
Student* Student::readStudent(std::istream &i){
std::string y;
i >> y;
return new Student(y);
}
int main(int argc, char* argv[]){
Student *stud3 = NULL;
std::cout << "\nPlease insert name for student:\n";
stud3 = Student::readStudent(cin);
return 0;
}
You are allocating on the heap using new and never freeing it, thus you run out of memory and get a bad_alloc. For every new there should be a delete.
This will not throw bad_alloc:
Student Student::readStudent(std::istream& i)
{
std::string y;
i >> y;
return Student(y);
}
Related
So i need to get code of the structure#1 (e[0]) but i get the following error;
"error: request for member 'get_code' in 'emp1', which is of pointer type 'Employee*' (maybe you meant to use '->' ?)"
i don't really understand how to fix this. Plus, it's an assigment so i'm bound to use structures,and also, i don't know what "->" is, but if it's any operator or something, im not allowed to use it cause we haven't been taught that yet.
(Answers to the similar question suggest using -> so that doesnt work for me.)
i also tried using *(emp1).get_code()
#include <iostream>
#include <string.h>
using namespace std;
struct Employee{
private:
string code;
string name;
float salary;
public:
void set_code(string c){
code=c;
}
void set_name(string n){
name=n;
}
void set_sal(float s){
salary=s;
}
string get_code(){
return code;
}
string get_name(){
return name;
}
float get_sal(){
return salary;
}
};
int main(void) {
Employee e[2],*emp1,*emp2;
string c,n;
float s;
for (int i=0;i<2;i++){
cout<<"Enter code for employee "<<i+1;
cin>>c;
e[i].set_code(c);
cout<<"Enter name for employee "<<i+1;
cin>>n;
e[i].set_name(n);
cout<<"Enter salary for employee "<<i+1;
cin>>s;
e[i].set_sal(s);
}
*emp1=e[0];
cout<<emp1.get_code();
}
First of all, this line is not correct:
*emp1=e[0];
What your line does is assign the structure value 'e[0]' to the structure at pointer 'emp1'. However, the pointer 'emp1' is never initialized, so you'd end up writing in an invalid location.
What you need to write is:
emp1=&e[0];
That will actually set emp1 to the location of 'e[0]'.
Secondly, the symbol '->' is what you use when you want to access a member of a pointer.
In this case you should not write:
cout<<emp1.get_code();
But rather:
cout<<emp1->get_code();
The reason why you need to write that is that 'emp1' is a pointer. Thus, to access its member 'get_code', you need to use the symbol '->'.
I have written this code snippet:
int main()
{
char *name;
cin >> name;
return 0;
}
After compiling it gives error as: "uninitialsed local variable 'name' used". I don't understand why this is happening. Please explain what is my problem.
Thanks.
char* is a pointer to a char which, at the moment, doesn't 'point' anywhere. You could allocate some memory and point to that.
char* name = new char[64];
cin >> name;
delete[] name;
However, you can avoid this requirement by using std::string. Have a look at some examples here: http://www.cplusplus.com/forum/articles/6046/
Unless you allocate memory for name you are writing to an uninitialized pointer.
Try this:
#include <iostream>
int main()
{
char *name = new char[100];
std::cin >> name;
delete [] name;
return 0;
}
when i compile the program i get an error about int when i create a bookClass object using the 2 argument constructor. the error has somerthing to do with the integer argument parsed to the constructor. the program is:
#include <iostream>
#include <string>
using namespace std;
class bookClass{
private:
string bookName;
int bookNumber;
public:
void setName(string c){
bookName=c;
}
void setNumber(int d){
bookNumber=d;
}
string getName(){
return bookName;
}
int getNumber(){
return bookNumber;
}
bookClass(string a, int b){
bookName=a;
bookNumber=b;
}
};
int main()
{
int numberr;
string name;
cout << "Enter the book name: ";
cin >> name;
cout << "\nEnter the book number: ";
cin >> numberr;
bookClass book=new bookClass(name, numberr);
cout << "\n\nThe book " << book.getName() << " has book number " <<
book.getNumber() << endl;
return 0;
}
Compiling your code I didn't get the error you suggested. However, there is an issue with this line:
bookClass book = new bookClass(name, numberr);
C++ is not Java. new returns a pointer to memory dynamically allocated for the given class.
What you want is just:
bookClass book (name, numberr);
The problem with your code is simple. I suppose you were programming in Java or C# before C++. In C++ we call new operator only if we want to create an object explicitely on heap (and get a pointer to it).
bookClass* book=new bookClass(name, numberr);
However, now you are in troubles because you are calling book.getName() where book is of type pointer to something and it has no member getName(). You have to first dereference that pointer and then call a member function (*book).getName(); or simply book->getName();.
However, since C++'s objects do not have to be on the heap (Java objects have to) you can create an object without new operator using bookClass book(name, numberr);
I have basic file handling code of reading file named"student.dat" using visual studio.
the output reads the file and displays the result in console but visual studio pops up the dialog as
code:
#include<iostream>
#include<fstream>
#include<conio.h>
#include<string>
using namespace std;
class student
{
int admno;
// char name[20];
string name;
public:
void getdata()
{
cout<<"\n\nEnter The Name of The Student ";
//gets(name);
cin>>name;
getch();
cout<<"\nEnter The admission no. ";
cin>>admno;
// getch();
}
void showdata()
{
cout<<"\nAdmission no. : "<<admno;
cout<<"\nStudent Name : ";
cout<<name;
//puts(name);
}
int retadmno()
{
return admno;
}
};
int main()
{
student obj;
ifstream fp1;
fp1.open("student.dat",ios::binary);
while(fp1.read((char*)&obj,sizeof(obj)))
{
obj.showdata();
}
fp1.close();
return 0;
}
You are allowed to load raw data only to some POD objects. This line is an error:
fp1.read( (char*)&obj,sizeof(obj) );
because student contains std::string. std::string contains a pointer to a memory block which becomes invalid and totally useless after the object is destroyed. It means the data you load to std::string is just a garbage.
I'd think about object serialization. Boost serialization is a good way to start.
You try to store/load an object to a file, which is invalid.
while(fp1.read((char*)&obj,sizeof(obj)))
Objects may contain references to memory (std::string e.g.) that are invalid after loading. You have to provide serialization for your objects or use plain structs without pointers or references to store your data. E.g.:
struct {
int admno;
char[20] name;
}
If you need strings with variable length, you may use a string store:
struct {
int admno;
size_t name_index;
}
std::vector<std::string> names;
To store, iterate over your names and save length and .c_str of each std::string. To read, do it the other way around and read length into n, read n bytes into a buffer and construct a std::string out of the buffer.
You might have a look at http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html
You never call GetData so admno is not instantiated in ShowData
I am trying to take data from a file and store it in a Object that I have created. I keep running into a segmentation fault, but I am not sure what is causing it. Here is the code:
Object<string> populateObj(Object<string>&,string);
string clean(string);
int main(){
string dictionaryFile;
ifstream inFile;
ofstream outFile;
Object<string> obj1;
cout << "Enter the name of the Dictionary file" << endl;
cin >> dictionaryFile;
obj1 = populateObj(obj1,dictionaryFile);
}
Object<string> populateObj(Object<string> &obj,string fileName){
ifstream file;
string words = "";
file.open(fileName);
if(file.is_open()){
while(!file.eof()){
file >> words;
obj.add(words);
}
}
else
cout << "could not open file..." << endl;
return obj;
}
This may or may not be causing your problem, but this is wrong:
if(file.is_open()){
while(!file.eof()){
file >> words;
obj.add(words);
}
}
Try instead:
while (file >> words) {
obj.add(words);
}
Your original code tests EOF too early to be useful.
int main(){
//...
Object<string> obj1;
//...
obj1 = populateObj(obj1,dictionaryFile);
}
Object<string> populateObj(Object<string> &obj,string fileName){
//...
obj.add(words);
//...
return obj;
}
You're unnecessarily overwriting the object. Don't do this. While technically it could work, it's a bad habit (and it points to your copy operator having a bug in it).
Instead, return a reference (if anything) and don't overwrite the object. Also, don't pass in the dictionary string by value, pass it by const reference:
int main(){
//...
Object<string> obj1;
//...
populateObj(obj1,dictionaryFile);
}
Object<string>& populateObj(Object<string> &obj,const string& fileName){
//...
obj.add(words);
//...
return obj;
}
I expect the problem is in your Object class. If you keep your existing code, and define the object like this, then it runs without error:
template<class T> class Object {
public:
void add(T);
};
template <class T> void Object<T>::add(T val)
{
cout << "Adding " << val << "\n";
}
So you need to look at your Object class to see why it is failing. The most likely spot would be when the object is copied to return it, and then copied back over the original obj1. Does that class allocate memory, or use a member variable that isn't copy constructable?
If you take out that unnecessary return of the object you may "fix" the problem by avoiding the copy, but you may want to still fix up the object anyhow as otherwise this problem will probably just surface somewhere else when the object gets copied.