Breakpoint on delete[] when destroying char * - c++

I'm doing an assignment for class in which I can't use the string class. I need to use char* as arrays and doing arithmetic with them.
My code being executed in main is the following: I create 2 myString objects and I add them. Then this is done correctly. Both strings get concatenated. but, there's a breakpoint at delete[] str. Can you tell me where I do wrong exactly? I'd like to understand what happens.
myString& myString :: operator+ (const myString& s)
{
myString tmp; //myString temporal
strcpy_s(tmp.str, strlen(str)+1,str); //STR is copied to tmp.str
Alloc(strlen(s.str)+size+1); //Then memory is allocated for both values
strcpy_s(str, strlen(tmp.str)+1, tmp.str); //WE COPY TMP.STR INTO STR NOW WITH ENOUGH SIZE FOR THE NEXT...
strcat_s(str, strlen(s.str) + size+1, s.str); //..ARGUMENT WE CONCATENATE 2 MYSTRING.STR
return (*this);
}
This is the class myString
class myString
{
public:
//Propietats
int size;
char* str;
//CONSTRUCTORS
myString();
myString(const myString&);
//myString(myString&);
myString(const char*, ...);
//Utilities
int Len(char*);
const void Clear();
const void Alloc(const int);
//Operators
bool operator== (const myString&) const;
bool operator== (const char* s) const;
const myString& operator= (myString&);
const myString& operator= (const char* s);
bool operator!= (const myString&) const;
bool operator!= (const char* s) const;
myString& operator+ (const myString&);
myString& operator+ (const char*);
//Metodes
~myString()
{
delete[] str; // **ERROR** THERE'S A BREAKPOINT HERE
}
};
#endif
My error is that there's a breakpoint in delete[] str; And I don't know what to do. It means there's an overflow? How do I solve it?
I'm quite new to pointer arithmetic so don't be harsh.

myString& myString :: operator+ (const myString& s)
{
myString tmp; //myString temporal
tmp.Alloc(strlen(str)+1); // Add this line
strcpy_s(tmp.str, strlen(str)+1,str); //STR is copied to tmp.str
...
You are not allocating room in tmp string. Once allocated, it should work fine.

You are probably corrupting the heap.
myString tmp;
What is tmp.str after this instruction ? Is tmp.str a NULL pointer ? A pointer to a buffer with some default size ?
strcpy_s(tmp.str, strlen(str)+1,str);
Did you make sure tmp.str has room for strlen(str)+1 char ?
You probably should call tmp.Alloc(strlen(str)+1) before this instruction.

Related

How to solve "no operator "[]" matches these operands" when I use smart pointer

Here is my code:
class Mystring
{
private:
unsigned int size;
shared_ptr<char>message=make_shared<char>();
public:
Mystring(const char* input):size(strlen(input)),message(make_shared<char>(size+1))
{cout<<"Created"<<endl;memcpy(this->message,input,size+1);}
Mystring(const Mystring& other):size(other.size),message(make_shared<char>(size+1))
{cout<<"Created"<<endl;memcpy(this->message,other.message,size+1);}
~Mystring(){cout<<"Deleted"<<endl;}
friend ostream& operator<<(ostream& Cout,const Mystring& mystring)
{Cout<<mystring.message<<endl;return Cout;}
char& operator[](const unsigned int index)
{return this->message[index];}
};
I want to use smart pointers and operator [] properly. How can I solve these problems:
no suitable conversion function from "std::shared_ptr<char>" to "void *" exists
no operator "[]" matches these operands
So lots of problems with this code
You have a shared char array, so the type is shared_ptr<char[]> not shared_ptr<char>. This also means you cannot use make_shared, since it doesn't work with arrays.
If you want to access the pointer to the array use get().
Your copy constructor allocates a new array, which is a bit weird since why are you using shared_ptr, if you don't want to share the array? On the other hand the default assignment operator will share the array, so you have a strange situation where sometimes when you copy Mystring you will share the array, and sometimes you won't.
Various other minor issues
Here's a version that works
class Mystring
{
private:
size_t size;
shared_ptr<char[]> message;
public:
Mystring(const char* input) : size(strlen(input)), message(new char[size+1])
{
cout<<"Created"<<endl;
memcpy(message.get(), input, size+1);
}
Mystring(const Mystring& other): size(other.size), message(other.message)
{
cout<<"Created"<<endl;
}
~Mystring()
{
cout<<"Deleted"<<endl;
}
friend ostream& operator<<(ostream& Cout,const Mystring& mystring)
{
Cout<<mystring.message.get()<<endl;return Cout;
}
char& operator[](size_t index)
{
return message.get()[index];
}
};
I changed the copy constructor so that it does share the underlying array. You can change it back if you wish. However is you want a Mystring which does not share it's array with other Mystring objects then it would make more sense to use unique_ptr<char[]> instead of shared_ptr.

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.

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

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;
}

overload array operator for mystring class

I need help figuring out how to overload the array operator for a MyString class that I have to create. I already have everything else figured out, but the arrays are giving me trouble, for some reason.
Here is my header file:
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring> // For string library functions
#include <cstdlib> // For exit() function
using namespace std;
// MyString class: An abstract data type for handling strings
class MyString
{
private:
char *str;
int len;
public:
// Default constructor.
MyString()
{
str = 0;
len = 0;
}
// Convert and copy constructors.
MyString(char *);
MyString(MyString &);
// Destructor.
~MyString()
{
if (len != 0)
delete [] str;
str = 0;
len = 0;
}
// Various member functions and operators.
int length() { return len; }
char *getValue() { return str; };
MyString operator+=(MyString &);
MyString operator+=(const char *);
MyString operator=(MyString &);
MyString operator=(const char *);
bool operator==(MyString &);
bool operator==(const char *);
bool operator!=(MyString &);
bool operator!=(const char *);
bool operator>(MyString &);
bool operator>(const char *);
bool operator<(MyString &);
bool operator<(const char *);
bool operator>=(MyString &);
bool operator>=(const char*);
bool operator<=(MyString &);
bool operator<=(const char *);
MyString operator [](MyString *);
// Overload insertion and extraction operators.
friend ostream &operator<<(ostream &, MyString &);
friend istream &operator>>(istream &, MyString &);
};
#endif
What would the body look like for MyString::operator []?
MyString MyString::operator [](MyString *)
{
... what goes here
}
The syntax for using the array operator with an object of the given class is:
MyString s("Test");
char c = s[0];
The argument to the function is an integral value.
Hence, the operator needs to be declared as:
// The non-const version allows you to change the
// content using the array operator.
char& operator [](size_t index);
// The nconst version allows you to just get the
// content using the array operator.
char operator [](size_t index) const;
MyString MyString::operator [](MyString *)
That's not how you should typically use a subscript operator.
What do you expect when you are using the [] operator? By the way you declared it, you are using a string pointer as argument, and receiving a string as return.
Usually, you pass an index type (commonly an unsigned-integer like size_t) and return the character at that position. If that's what you want, you should do something along these lines:
char& MyString::operator [](size_t position)
{
// some error handling
return str[position];
}
char MyString::operator [](size_t position) const { /* ... */ }
For overall guidelines on overloading operators, take a look at What are the basic rules and idioms for operator overloading?.
Also, I would point out that your destructor is a bit odd:
if (len != 0)
delete [] str;
str = 0;
len = 0;
Your indentation level suggests that you expect everything to happen inside the if statement, but only the first one will. That is not particularly dangerous in this case, because only the delete would suffice.
There is no problem in deleteing a null pointer, and str and len will be destroyed shortly after, so you don't have to bother resetting them.

Error in my str class

I'm making my own string class but I got a problem reading the characters of the string while using strlen() to do that.
/****str.h****/
class str
{
private:
char *m_ptr;
unsigned int m_size;
//unsigned int m_capacity;
public:
str();
str (const char *);
str (const str &);
~str (){if (m_size != 0) delete [] m_ptr;};
char *data() {return m_ptr;};
//Sobrecarga de operadors.
str operator=(str);
friend std::ostream& operator<<(std::ostream &, str);
};
I got the error using the constructor initialized with a c-string constant.
/****str.cpp****/
//Default constructor.
str :: str ()
{
m_ptr = new char [1];
m_ptr[0] = '\0';
m_size = 0;
//m_capacity = 10;
}
str :: str(const char *sm_ptr)
{
m_size = strlen(sm_ptr); //HERE IS WHERE THE ERROR OCCURS.
m_ptr = new char[m_size + 1];
strcpy(m_ptr, sm_ptr); //Copies the C string pointed by source into the array pointed by destination, including the terminating null character
}
//Copy constructor.
str :: str(const str &right)
{
m_ptr = new char [right.m_size];
strcpy (m_ptr, right.m_ptr);
m_size = right.m_size;
}
str str::operator=(str right)
{
if (m_size != 0) delete [] m_ptr;
m_ptr = new char [right.m_size + 1];
strcpy(m_ptr, right.m_ptr);
m_size = right.m_size;
return *this;
}
std::ostream &operator<<(std::ostream &strm, str obj)
{
strm << obj.m_ptr;
return strm;
}
0x0053fdd0 {m_ptr=0xcccccccc m_size=3435973836 } str *
Changing the assignment operator declaration to
str& operator=(str&);
or even
const str& operator=(const str&);
would eliminate creation of temporary objects. Check out this article for more information on passing arguments to functions.
There are a couple of other issues. For example in default constructor you allocate memory but you don't set size so it's never going to be freed. Also, in copy constructor and assignment operator it's almost always a good idea to check for self-assignment.