I'm trying to make a class that contains a pointer, which is the core of a dynamic array.
How to overload the operator >> so I can cin >> to the pointer without know how many characters are going to put?
I was trying:
#include <iostream>
class MyString
{
private:
char* str;
size_t length;
public:
//some code here
friend std::istream& operator>>(std::istream& is, const MyString& other)
{
is >> other.str;
return is;
}
}
and this happened when I try to cin a string:
HEAP CORRUPTION DETECTED
Is there a way to read a string, assign it to my string, and won't use the std::string header?
(I was trying to make a string class that doesn't depend on std::string)
A naive implementation would use is.get() to retrieve one character at a time, and append it to other, resizing if needed. And stop when std::isspace(chr) is true, of course. For that, you need to dynamically allocate memory and keep track of how much space you are using / have available in the implementation of MyString.
Here is the skeleton for that; you probably need to implement the append() method.
friend std::istream& operator>>(std::istream& is, MyString& other) {
while (true) {
int chr = is.get();
if (is.eof() || std::isspace(chr)) {
break;
}
other.append((char)chr);
}
return is;
}
#include <iostream>
#include <string.h>
class MyString
{
private:
size_t length;
char* str;
void getInput(std::istream&is)
{
char c='\0';
while(c!='\n')
{
is.get(c);
length++;
str=(char*)realloc(str, length);
if(c=='\n')
{
str[length-1]='\0';
}
else{
str[length-1]=c;
}
}
}
public:
MyString()
{
length=0;
str=new char[1];
str[0]='\0';
}
//some code here
friend std::istream& operator>>(std::istream& is, MyString& other)
{
std::cout<<"Enter String: ";
other.getInput(is);
return is;
}
void printString()
{
std::cout<<str<<std::endl;
}
~MyString()
{
delete[]str;
length=0;
}
};
int main()
{
MyString s;
std::cin>>s;
s.printString();
}
Related
I have function, which recieves coeffecents of polynomial via istream input. Im struggling with implementing this piece of code into it (can't fully understand how istream& works), so i can shield it from incorrect input. :
while (!std::cin.good())
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "error";
std::cin >> A;
}
Into the function itself:
std::istream& operator>>(std::istream& s, Polynom& c)
{
for (int i = 0; i <= c.degree; i++)
s >> c.coefficents[i];
return s;
}
Needless to say, that's how it is implemented in main()
std::cin >> A;
Polynom class:
class Polynom
{
private:
int degree;
double* coefficents;
public:
Polynom();
Polynom(int size);
Polynom(const Polynom&);
~Polynom();
int get_degree();
double get_coefficents(int);
Polynom operator+(const Polynom&);
Polynom operator-(const Polynom&);
Polynom operator*(double p);
void operator=(const Polynom&);
friend std::ostream& operator<< (std::ostream& s, const Polynom& c);
friend std::istream& operator>> (std::istream& s, Polynom& c);
double& operator()(int i)
{
return coefficents[i];
}
};
Any hints or optimal solutions are welcomed :)
Expanding my comment to an answer, it's possible to make a function which takes the stream and uses the read-validation loop inside it to get the value.
Then in your operator>> overload you call this function to get each value.
Perhaps something like this:
template<typename T>
bool get_value(std::istream& input, T& value)
{
while (!(input >> value))
{
// If end of file, don't attempt any more validation
if (input.eof())
{
return false;
}
// Clear the error
input.clear();
// Ignore the rest of the line
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
// When the loop ends, we have successfully read a value from the stream
// Return true to tell that
return true;
}
You could use it as:
std::istream& operator>>(std::istream& s, Polynom& c)
{
double value;
for (int i = 0; i <= c.degree && get_value(s, value); i++)
c.coefficents[i] = value;
return s;
}
So I have this code where an object of class Group has vector with objects from class Student. I am already writing information about the students from the vector into a file but I have problem with reading this information back. How can I do that?
Here is my code so far:
class Group
{
private:
string name;
vector <Student*> studentList;
public:
~Group();
Group(void);
Group(string s);
void addStudent(string name,int age,int stNum);
void removeStudent(int stNum);
friend ostream& operator << (std::ostream& out, const Group& g) {
out << g.name << "\n";
out << g.studentList.size() << "\n";
for (unsigned i=0;i<g.studentList.size();i++) {
out<< g.studentList[i]->getStudentName()<<"\n";
out<< g.studentList[i]->getStudentAge()<<"\n";
out<< g.studentList[i]->getStudentNumber()<<"\n"<<endl;
}
return out;
}
friend istream& operator>>(std::istream& in, Group& g){
in >> g.name;
for (unsigned i=0;i<g.studentList.size();i++) {
//READ DATA FROM FILE
}
return in;
}
};
Gathering up the commentary. Note this pushes the hard part, the reading and writing, into Student and I left that bit blank. Normally I'd do it because I'm evil, but apparently in this case it is already written.
Major changes:
No Student pointers. Lest memory management overhead and better cache friendliness! By Grabthar's hammer. What a savings.
Student does the Student reading and writing.
std::vector handles the element counting so it doesn't need to be stored in and read from the output. Note: This could slow the reading down a little because you can't pre-allocate storage in the vector.
#include <string>
#include <iostream>
#include <vector>
// note the lack of using namespace std;
// it can be problematic, and especially so in a header.
class Student
{
//fill in the blanks
friend std::ostream& operator <<(std::ostream& out, const Student& s)
{
//fill in the blanks
return out;
}
friend std::istream& operator >>(std::istream& in, const Student& s)
{
//fill in the blanks
return in;
}
};
class Group
{
private:
std::string name;
std::vector<Student> studentList; // death to pointers!
public:
//~Group(); // Don't need a destructor without the pointer
Group(void);
Group(std::string s);
void addStudent(std::string name, int age, int stNum);
void removeStudent(int stNum);
friend std::ostream& operator <<(std::ostream& out, const Group& g)
{
out << g.name << "\n";
//out << g.studentList.size() << "\n"; not necessary. vector handles it.
for (std::vector<Student>::const_iterator it = g.studentList.cbegin();
it != g.studentList.cend();
++it)
{
if (!(out << *it))// let Student's << do all the work
{ // write failed. Might as well stop trying to write.
break;
}
}
return out;
}
friend std::istream& operator>>(std::istream& in, Group& g)
{
in >> g.name;
Student temp;
while (in >> temp) // let Student's >> do all the work
{
g.studentList.push_back(temp);
}
return in;
}
};
I try to overload ostream operator in a class Student as follows:
//Student.h
class Student
{
public:
Student(){}
~Student(){}
friend std::ostream& operator<< (std::ostream&,const Student&);
friend std::istream& operator>> (std::istream&,const Student&);
private:
char* snum;
};
//Student.cpp
#include "Student.h"
std::ostream& operator<< (std::ostream& output,const Student& c)
{
output<<c.snum<<", "<<c.name<<", "<<c.email<<endl;
return output;
}
std::istream& operator>> (std::istream& input,const Student& cN)
{
cout<<"Input number: ";
input>>cN.snum;
return input;
}
//main.cpp
#include "Student.h"
int main()
{
Student st;
std::cin >> st;
std::cout << st << std::endl;
return 0;
}
But when i input the snum,i get error message "Segmentation Fault".
I change char* snum; to char snum;,it return compiler error The operation "std::istream>> const char" is illegal.
Thank you for help.
You need that snum will point on allocate memory and then you can input it with data, for exemple:
char* p_var = new char[20]; // 20 bytes allocation
// ... using p_var
delete[] p_var; // Releasep_var memory
In your case, you should do the allocation in the Ctor and the release in the Dtor.
you can read this for more info:
http://www.cplusplus.com/doc/tutorial/basic_io/
tell me if your problem got solved by using below changes...
class Student
{
private:
char snum;
char name;
char email;
public:
Student(){};
~Student(){};
friend std::ostream& operator<< (std::ostream&,Student&);
friend std::istream& operator>> (std::istream&,Student&);
};
std::ostream& operator<< (std::ostream& output,Student& c)
{
output<<c.snum<<", "<<c.name<<", "<<c.email<<endl;
return output;
}
std::istream& operator>> (std::istream& input, Student& cN)
{
cout<<"Input number: ";
input>>cN.snum;
input>>cN.name;
input>>cN.email;
return input;
}
int main()
{
Student st;
std::cin >> st;
std::cout << st << std::endl;
return 0;
}
use string or char array or assign char *x some memory before using for cin...
#include<iostream>
#include<cstring>
using namespace std;
class Animal
{
protected:
int age;
char* name;
public:
Animal()
{
name=new char[1];
age = 0;
strcpy(name," ");
}
Animal(int _age, char* _name)
{
age=_age;
name = new char[strlen(_name)+1];
strcpy(name, _name);
}
~Animal()
{
delete[] name;
}
friend istream& operator >>(istream& in, Animal& a);
friend ostream& operator <<(ostream& out, const Animal& a);
};
istream& operator >>(istream& in, Animal& a)
{
in>>a.name>>a.age;
return in;
}
ostream& operator <<(ostream& out, const Animal& a)
{
out<<a.name<<a.age;
return out;
}
int main()
{
Animal a;
cin>>a;
cout<<a;
return 0;
}
This piece of code gives me the opportunity to enter a, then prints it and then the screen freezes and stops working. If I delete the destructor, it works properly. Why is this happening? And is it because of the destructor really?
You allocate a C-string having the size 1 and copy the C-string " " having the size 2 to it. Also you read an unknown amount of characters to the name in 'istream& operator >>(istream& in, Animal& a)`. Both will corrupt the memory the name is pointing to and both can be easily fix by using std::string:
class Animal
{
protected:
int age;
std::string name;
public:
Animal()
: age(0)
{}
Animal(int age_, std::string name_)
: age(age_), name(name_)
{}
};
This avoids writing a destructor and copy-constructor and assignment operator, which are missing in your code (See: Rule of three).
If you really don't want to use std::string, your best bet is something in the line of (live at coliru):
#include<iostream>
#include<cstring>
using namespace std;
class Animal {
private:
// copy a string
inline static char* dstr(const char* string) {
if( !string ) return NULL;
size_t l = strlen(string);
if( !l ) return NULL;
return strcpy(new char[++l], string);
}
protected:
int age;
char* name;
public:
// initialize an "empty" Animal
Animal() : age(0), name(NULL) {}
// initialize an animal by age and name
Animal(int _age, const char* _name): age(_age), name(dstr(_name)) {}
// initialize an animal from another animal:
// copy the name string
Animal(const Animal& _a): age(_a.age), name(dstr(_a.name)) {}
// assign an animal from another animal:
// first delete the string you have, then copy the string
Animal& operator=(const Animal& _a) {
// for exception-safety, save the old "name" pointer,
// then try to allocate a new one; if it throws, nothing happens
// to *this...
char* oldname = name;
name = dstr(_a.name);
age = _a.age;
delete[] oldname;
return *this;
}
// if C++11
// we have something called "move" constructor and assignment
// these are used, for instance, in "operator>>" below
// and they assume that _a will soon be deleted
Animal(Animal&& _a): Animal() {
swap(age, _a.age);
swap(name, _a.name);
}
Animal& operator=(Animal&& _a) {
swap(age, _a.age);
swap(name, _a.name);
return *this;
}
~Animal() { delete[] name; }
friend ostream& operator <<(ostream& out, const Animal& a);
};
istream& operator >>(istream& in, Animal& a) {
const size_t MAX_ANIMAL_NAME = 2048;
int age;
char n[MAX_ANIMAL_NAME+1];
if( in.getline(n, MAX_ANIMAL_NAME) >> age )
a = Animal(age, n);
return in;
}
ostream& operator <<(ostream& out, const Animal& a) {
return out<<a.name<<endl<<a.age<<endl;
}
int main() {
Animal a { 23, "bobo" };
cout<<a;
cin>>a;
cout<<a;
}
This does not leak memory, does not have undefined behaviours, and does not have buffer overruns.
You can also segregate the "need to manage memory" to a separate class:
#include<iostream>
#include<cstring>
using namespace std;
class AnimalName {
private:
char *n;
inline static char* dstr(const char* string) {
if( !string ) return NULL;
size_t l = strlen(string);
if( !l ) return NULL;
return strcpy(new char[++l], string);
}
public:
AnimalName() : AnimalName(NULL) {}
AnimalName(const char *_n) : n(dstr(_n)) {}
AnimalName(const AnimalName& _n) : n(dstr(_n.n)) {}
// see exception-safety issue above
AnimalName& operator=(const AnimalName& _n) { char *on = n; n = dstr(_n.n); delete[] on; return *this; }
AnimalName(AnimalName&& _n) : AnimalName() { swap(n, _n.n); }
AnimalName& operator=(AnimalName&& _n) { swap(n, _n.n); return *this; }
~AnimalName() { delete[] n; }
operator const char*() const { return n; }
friend istream& operator>>(istream& i, AnimalName& n) {
const size_t MAX_ANIMAL_NAME = 2048;
char name[MAX_ANIMAL_NAME+1];
if( i.getline(name, MAX_ANIMAL_NAME) )
n = name;
return i;
}
};
class Animal {
protected:
int age;
AnimalName name;
public:
// initialize an "empty" Animal
Animal() : age(0) {}
// initialize an animal by age and name
Animal(int _age, const char* _name): age(_age), name(_name) {}
friend ostream& operator <<(ostream& out, const Animal& a) {
return out<<a.name<<endl<<a.age<<endl;
}
};
istream& operator >>(istream& in, Animal& a) {
AnimalName n;
int age;
if( in >> n >> age )
a = Animal(age, n);
return in;
}
int main() {
Animal a { 23, "bobo" };
cout<<a;
cin>>a;
cout<<a;
return 0;
}
This way you get to follow the "rule of zero" (basically, classes that do not have the sole responsibility of managing memory/resources should not manage memory and therefore should not implement copy/move-constructors, assignments, or destructors.)
And that takes us to the real reason why you should use std::string: it not only does the memory management for you, but it also takes good care of your IO needs, eliminating the need for a "maximum animal name" in your example:
#include<iostream>
#include<string>
using namespace std;
class Animal {
protected:
string name; // name first, for exception-safety on auto-gen assignment?
int age;
public:
// initialize an "empty" Animal
Animal() : age(0) {}
// initialize an animal by age and name
Animal(int _age, const string& _name): age(_age), name(_name) {}
friend ostream& operator <<(ostream& out, const Animal& a) {
return out<<a.name<<endl<<a.age<<endl;
}
};
istream& operator >>(istream& in, Animal& a) {
string n;
int age;
if( getline(in, n) >> age )
a = Animal(age, n);
return in;
}
int main() {
Animal a { 23, "bobo" };
cout<<a;
cin>>a;
cout<<a;
}
A simple fix is to use std::string for your strings.
It almost doesn't matter what the specific errors you get are. But just to cover that, already in the constructor of Animal,
Animal()
{
name=new char[1];
age = 0;
strcpy(name," ");
}
you have Undefined Behavior by allocating just a single element array and then using strcpy top copy two char values there. Overwriting some memory after the array.
Then in operator>> the UB trend continues.
And so forth.
Use std::string.
Your memory management is wrong, which is corrupting the memory. You are allocating space for one character for name. But
strcpy(name," ");
will pass beyond the memory you allocated, since cstring is null terminated, it will put actually two character, effectively corrupting your memory ( you are accessing memory that is not allocated by your program). It itself has undefined behavior.
Further you are deleting an apparently unknown amount of memory in the destructor, which has also undefined behavior.
There are several bugs in your code.
The first one is in the constructor
Animal()
{
name=new char[1];
age = 0;
strcpy(name," ");
}
String literal " " consists from two characters: the space character and the terminating zero '\0;. So you need to allocate dynamically 2 bytes
name=new char[2];
that to use after that function strcpy.
Or instead of string literal " " you should use "an empty" string literal "" that contains only the terminating zero '\0'.
The other bug in function
istream& operator >>(istream& in, Animal& a)
{
in>>a.name>>a.age;
return in;
}
As you initially allocated only 1 byte pointed to by name then you may not use operator
in>>a.name;
because you will overwrite memory that does not belong to the allocated extent.
For example you could define the operator the following way
std::istream& operator >>( std::istream& in, Animal &a )
{
char itsName[25];
in >> itsName >> a.age;
char *tmp = new char[std::strlen( itsName ) + 1];
std::strcpy( tmp, itsName );
delete [] name;
name = tmp;
return in;
}
In this case you could enter a name that does not exceed 24 characters.
Take into account that you need also to define a copy constructor and the copy assignment operator if you are going to assign one object to another.
I am kind of newbie to programming migrated from legacy turbo c++ to VS C++2012,I have a tough time catching up and i wanted to emulate the string library for TC. But i cant make the insertion operator work in this code....Please help Out. Could you tell the mistake i made in this code. And also why are we returning the object via reference for overloading.
#include<iostream>
#include<string>
namespace String
{
class string
{
char word[100];
int size;
public:
string()
{
size=0;
}
string(int sz)
{
size=sz;
}
string(char *Word)
{
strcpy(word,Word);
size=sizeof(*Word);
}
~string()
{
}
string &operator+(string Add)
{
strcat(word,Add.word);
return *this;
}
string &operator=(char *Word)
{
strcpy(word,Word);
return *this;
}
/*
ostream &operator<<(ostream &sout,string Show)
{
sout<<Show.word;
return sout;
}
*/
void Show()
{
std::cout<<word;
}
};
}
void main()
{
String::string A="ABCDEF";
String::string B="GHIJK";
String::string C;
C=A+B;
C.Show();
std::cin.ignore(2);
//std::cout<<C;
}
You should declare operator<< as a non-member function, because ostream will be taken as the 1st argument for operator<<, a user define type's member function can't satisfy it.
namespace String
{
class string
{
...
public:
ostream& put(ostream &sout) { sout << word; return sout; }
};
ostream& operator<<(ostream& sout, string Show) { return Show.put(sout); }
}
The output operator << has to be overloaded in the namespace, not the class itself if you want to be able to use it like so:
cout << my_class_object;
So, in the declaration of your class (string.h) add this line:
ostream &operator<<(ostream & sout,const string & Show);
And then in the definition file (string.cpp) in your namespace, not the class itself, ad this function:
ostream & operator<<( ostream & out, const bigint & data )
{
// the printing implementation
}