0xC0000005: Access violation reading location 0x00000000. issues with overloaded == operator - c++

Hi there I'm currently working on a program for a data structures course that I am taking and I'm working on a part of an overloaded extraction operator. I am currently receiving the error Access violation reading location 0x00000000. when I attempt to compare two My String Objects with one another. A MyString object is essentially a c String, here is the class definition
class MyString {
private:
char* str;
public:
MyString();
MyString(const char*);
MyString(const MyString&);
~MyString();
int length() const;
void read(istream&, char);
static const int MAX_INPUT_SIZE = 127;
MyString& operator=(const MyString&);
MyString& operator +=(const MyString&);
friend MyString operator +(const MyString&, const MyString&);
char operator[](int location)const;
char& operator[](int location);
friend ostream& operator<<(ostream&, const MyString&);
friend istream& operator>>(istream&, MyString&);
friend bool operator <(const MyString& left, const MyString& right);
friend bool operator <=(const MyString& left, const MyString& right);
friend bool operator >(const MyString& left, const MyString& right);
friend bool operator >=(const MyString& left, const MyString& right);
friend bool operator ==(const MyString& left, const MyString& right);
friend bool operator !=(const MyString& left, const MyString& right);
};
}
#endif
this is the overloaded == operator throwing the exception
bool operator ==(const MyString& left, const MyString& right) {
return strcmp(left.str, right.str) == 0;
}
this is the context in which i am making the comparison, assume that temp is a valid MyString object.
for (int i = 0; i < sizeof(cs_measure::Measure::unitStrings); i++) {
if (cs_measure::Measure::unitStrings[i] == temp) {
readMe.unit = i;
in >> readMe.unit;
}
}
this is the array that is being referenced in the for loop
const MyString Measure::unitStrings[] =
{ "dram", "tsp", "tbsp", "oz", "cup", "pint",
"qt", "gal", "peck", "bushel", "barrel", "acre_ft" };
This is my first time posting to stack overflow so I have left out any crucial information that may be useful for solving this issue please let me know and I would be happy to help.

As mentioned in the comments, sizeof(cs_measure::Measure::unitStrings) is not the number of items in the array cs_measure::Measure::unitStrings. It is the number of bytes the array occupies in memories.
Since the size in bytes is almost surely larger than the number of elements, you will access the array out-of-bounds in the loop, causing undefined behavior.
You can get the number of items in a built-in array with
std::size(cs_measure::Measure::unitStrings)
since C++17 (may require #include<iterator> if you have not included any container library header).
Or if you can't use C++17, you can define your own version of it, though the C++17 standard version is a bit more powerful. (from cppreference.com):
template <class T, std::size_t N>
constexpr std::size_t size(const T (&array)[N]) noexcept
{
return N;
}

Related

Compiler error "Pointer being freed was not allocated" only while using a foreach loop of custom objects in C++

I have an assignment where I build my own my string class. I made several MYString objects and put them in a vector. When I access the vector through subscript operator, I have no issue. But when I traverse through the vector using foreach loop, then I get a weird error ""Pointer being freed was not allocated"
Did I mess up my copy constructor?
Is my destructor and clear() function messed up?
header file is as follows:
class MYString{
friend std::ostream& operator<<(std::ostream&, const MYString&);
friend std::istream& operator>>(std::istream&, MYString&);
private:
static const int INITIAL_CAP = 20;
char* str;
static int getLength(const char*);
int cap; //capacity of the char array, in multiples of 20
int end; // location of the null terminator
int compareTo(const MYString& rhs);
void clear(); // to manually free memory
static int requiredCap(int end);
public:
MYString();
MYString(const MYString& mystr);
MYString(const char*);
~MYString();
MYString& operator=(const MYString& rhs);
char& operator[](int index);
const char& operator[](int index) const;
int length() const;
int capacity() const;
const char* c_str();
MYString operator+(const MYString& rhs);
int operator==(const MYString& rhs);
int operator>(const MYString& rhs);
int operator<(const MYString& rhs);
};
Here is some relevant function defintions
MYString::MYString(const MYString& rhs){
*this = rhs;
}
MYString& MYString::operator=(const MYString& rhs){
if (this == &rhs){
return *this;
}
clear();
cap = rhs.cap;
end = rhs.end;
str = new char[cap];
for (int i = 0; i < end; i++){
str[i] = rhs[i];
}
str[end] = '\0';
return *this;
}
MYString::~MYString(){
clear();
}
void MYString::clear(){
cap = 0;
end = 0;
delete[] str;
str = nullptr;
}
The main method is as follows:
#include "MYString.h"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(){
ifstream input;
input.open("file.txt");
if (input.fail()){
cout << "File error" << endl;
}
MYString s;
vector<MYString> v;
int count = 0;
v.push_back(MYString());
int index = 0;
while (input >> s){
if (count == 2){
v.push_back(MYString());
count = 0;
index++;
}
if (count < 2){
v[index] = v[index] + s;
count++;
}
}
for (MYString& str : v){
cout << str << endl;
}
Serious problem with your constructor:
MYString::MYString(const MYString& rhs){
*this = rhs;
}
Inside the body of your object, your data is not initialized, but you dereference this and assign to it. The data members contain garbage, including the pointer. In the assignment operator, you call clear, which calls delete[] on this garbage pointer. This is undefined behavior.
Implementing a constructor in terms of assignment is always wrong. Assignment is for replacing state of an initialized object with new state, while constructors provide initial state to uninitialized members. The object's lifetime has not even started UNTIL the constructor completes. Calling functions on an object whose life has not officially started is undefined behavior.
Your copy constructor needs to allocate memory and copy the data into it, similar to what you did in your assignment operator, but not cleaning up the old state first. Also, consider using strcpy instead of a loop to copy bytes. It will be faster.

Binary search tree << operator overload not working

I have 3 classes which creates a complete Binary search tree. The 3 classes are
1. DBentry(stores a name, IP address, and status),
2. TreeNode(points to its own DBentry, as well as entries to its left and right)
3. TreeDB(contains a root TreeNode and provides various functions to add, remove, update, and find DBentryobjects)
Inside DBentry I have friend ostream& operator <<(ostream& out, const DBentry& rhs);
Inside TreeDB I have friend ostream& operator<< (ostream& out, const TreeDB& rhs);
friend ostream& operator <<(ostream& out, TreeNode* rhs);
These overloading operators doesn't seem to work properly. Any help would be really helpful.
Class DBentry:
class DBentry {
private:
string name;
unsigned int IPaddress;
bool active;
public:
DBentry();
DBentry (string _name, unsigned int _IPaddress, bool _active);
~DBentry();
void setName(string _name);
void setIPaddress(unsigned int _IPaddress);
void setActive (bool _active);
string getName() const;
unsigned int getIPaddress() const;
bool getActive() const;
friend ostream& operator <<(ostream& out, const DBentry& rhs);
};
Class TreeNode:
class TreeNode {
private:
DBentry* entryPtr;
TreeNode* left;
TreeNode* right;
public:
TreeNode();
TreeNode(DBentry* _entryPtr);
~TreeNode();
void setLeft(TreeNode* newLeft);
void setRight(TreeNode* newRight);
TreeNode* getLeft();
TreeNode* getRight();
DBentry* getEntry() const;
bool find(string _name);
};
Class TreeDB has private:
TreeNode* root;
ostream& operator <<(ostream& out, const DBentry& rhs){
out<<rhs.name<<" : "<<rhs.IPaddress<<" : ";//<<rhs.active? (out<<"active"):(out<<"inactive")<<endl;
if(rhs.active)
out<<"active";
else
out<<"inactive";
out<<endl;
}
ostream& operator <<(ostream& out, TreeNode& rhs){
if(rhs.getEntry()!=NULL){
out << *(rhs.getLeft());
out << *(rhs.getEntry());
out << *(rhs.getRight());
}
}
ostream& operator<< (ostream& out, const TreeDB& rhs){
out << *(rhs.root);
}
ostream& operator <<(ostream& out, TreeNode& rhs) says the function returns a reference to an ostream. The code does not return an ostream reference, so the program will go on a merry little adventure into Undefined Behaviour.
At the very least, and there may be other problems in the unposted portions of the program, OP must
ostream& operator <<(ostream& out, TreeNode& rhs){
if(rhs.getEntry()!=NULL){
out << *(rhs.getLeft());
out << *(rhs.getEntry());
out << *(rhs.getRight());
}
return out; //<-- return the stream. Do not cross streams unless fighting Gozer.
}
The other operator<< overloads have the same flaw.

class method signature with *const* or without *const*?

I get the following error in Eclipse when trying to compile (c++)
../CardDeck.cpp:17:22: error: passing ‘const CardDeck’ as ‘this’ argument of ‘int CardDeck::size()’ discards qualifiers [-fpermissive]
if I change int size() method to int size() const the error msg is gone and its compiled. I dont know why ?
the .H file is the following :
#include "Card.h"
#include <vector>
using namespace std;
class CardDeck{
private:
vector<Card*> deck;
public:
int size();
CardDeck();
CardDeck(const CardDeck& rhs);
CardDeck& operator=(const CardDeck& rhs);
Card& draw();
Card& top();
bool isEmpty();
void clear();
int value();
CardDeck& operator+=(const CardDeck& rhs); /// not sure if to return ref
CardDeck& operator+(const CardDeck& rhs);
friend CardDeck& operator*(unsigned int num,CardDeck& rhs);
friend CardDeck& operator*(CardDeck& lhs,unsigned int num);
bool operator<=(const CardDeck& rhs );
bool operator>=(const CardDeck& rhs);
bool operator<(const CardDeck& rhs);
bool operator>(const CardDeck& rhs);
bool operator==(const CardDeck& rhs);
bool operator!=(const CardDeck& rhs);
Card* operator[](int i);
};
and the C++ file is :
#include "CardDeck.h"
int CardDeck::size() {
return this->deck.size();
}
CardDeck::CardDeck(){};
CardDeck::CardDeck(const CardDeck& rhs){
this->clear();
int i;
for (i=0;i<rhs.size();i++){
Card* current_card = rhs.deck[i];
Card* new_copy = new Card(*current_card);
this->deck.push_back(new_copy);
}
}
Card* CardDeck::operator[](int i) {
return this->deck[i];
}
void CardDeck::clear(){
vector<Card*>::iterator it ;
for(it=this->deck.begin();it != this->deck.end();++it){
Card* temp = *it;
this->deck.erase(it);
delete(temp);
}
}
In your copy constructor CardDeck::CardDeck(const CardDeck& rhs), rhs is a reference to a const CardDeck object.
So rhs.size() will not compile unless size() is explicitly marked as being const. That's what your compiler is telling you.
It's good practice to have your code as const-correct as possible as this prevents errant changes to the member data in a class. Really, isEmpty(), and possibly value() should be marked const too, as should all the overloaded relational operators.

Operator(s) too many parameters for this function?

Made my own string class (i.e. for homework obviously) and am getting odd syntax errors on two of my operators. My equality and add operators claim I have too many parameters (i.e. in my .h file), but then claim the method does not even belong to the class in my .cpp file!
I even made the equality operator a friend, but the intellisense still gives me the same error messages.
Does anyone know what I am doing wrong??
friend bool operator==(String const & left, String const & right);
string.h
bool operator==(String const & left, String const & right);
String const operator+(String const & lhs, String const & rhs);
string.cpp
bool String::operator==(String const & left, String const &right)
{
return !strcmp(left.mStr, right.mStr);
}
String const String::operator+(String const & lhs, String const & rhs)
{
//Find the length of the left and right hand sides of the add operator
int lengthLhs = strlen(lhs.mStr);
int lengthRhs = strlen(rhs.mStr);
//Allocate space for the left and right hand sides (i.e. plus the null)
char * buffer = new char[lhs.mStr + rhs.mStr + 1];
//Copy left hand side into buffer
strcpy(buffer, lhs.mStr);
//Concatenate right hand side into buffer
strcat(buffer, rhs.mStr);
//Create new string
String newString(buffer);
//Delete buffer
delete [] buffer;
return newString;
}
You need to define operator== outside the class:
bool String::operator==(String const & left, String const &right)
^^^^^^^^ REMOVE THIS
If operator+ is also a friend, it too needs to be defined as a free function (i.e. outside the class).

Set with Custom String Class Problem

I have written a custom string class.
I want to use STL set with it. I have overloaded operator <
But still its giving me problem
error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const String' (or there is no acceptable conversion)
1> could be 'String &String::operator =(const String &)'
1> 'String &String::operator =(const char *)'
1> 'String &String::operator =(const wchar_t *)'
1> while trying to match the argument list '(const String, const String)'
I guess, It is asking for overloaded operator= (const String , const String)
But its impossible to create such an overloaded function
My String class is this
String ();
String (const char * pStr);
String (const long int pData);
String (const double pData);
String (const int pData);
String (const wchar_t * pStr);
//Copy Constructors
String (const String& rhs);
String (const String& rhs, const int pStartIndex, const int pNumChar);
//Overloaded Operators
String & operator= (const String & rhs);
String & operator= (const char * rhs);
String & operator= (const wchar_t * rhs);
String operator+ (const String& rhs);
//String & operator+= (const char ch);
String & operator+= (const String& rhs);
friend bool operator== (const String& lhs, const String& rhs);
friend bool operator< (const String& lhs, const String& rhs) {
return strcmp(lhs.vStr, rhs.vStr);
}
friend ostream& operator<< (ostream& ostr, String& rhs);
char & operator[] (int pIndex);
char operator[] (int pIndex) const;
const char * String::Buffer () const;
wchar_t * GetTChar();
int String::GetLength () const;
~String ();
"no operator found which takes a left-hand operand of type 'const String'"
it seem you have an expression like
a=b;
where both a and b are const String.
You cannot assign to a const (although the compiler looks desperately seeking for an implementation of such an assignment)
OK, well I can only answer the question you've posed with the information you've given, and the answer is that this works for me.