Receiving an exception in overloaded operator >> section - c++

So I've overloaded an operator ">>" for my class MyString. It was supposed to read information from text file to a custom-made string, however I'm getting an exception when I'm trying to fill string char by char. Text.txt contains simply "xyz"
Main.cpp:
#include "MyString.h"
#include <fstream>
#include <iostream>
//TO-DO 1 CharArr for all
int main() {
MyString NewString;
ifstream In("Text.txt");
In >> NewString;
cout << NewString << endl;
system("pause");
return 0;
}
Constructors:
MyString::MyString() {
StringLength = 0;
Pointer = nullptr;
}
MyString::MyString(const char* String) {
for (int i = 0; String[i]; i++)
StringLength++;
Pointer = new char[StringLength + 1];
char *Source = (char *)String;
char *Destination = (char *)Pointer;
for (int i = 0; i < StringLength + 1; i++)
Destination[i] = Source[i];
}
Operator:
istream &operator>>(istream &In, MyString &String) {
int FileStringLength = 0;
char Character;
if (String.Pointer != nullptr)
delete[] String.Pointer;
while (In.get(Character) && Character != '\n')
FileStringLength++;
if (FileStringLength < 1000 && FileStringLength != 0) {
String.StringLength = FileStringLength;
In.clear(), In.seekg(0, ios::beg);
for (int i = 0; In.get(Character) && Character != '\n'; i++)
String.Pointer[i] = Character; // I get an exception here
}
else if (!FileStringLength) {
cout << "File is empty." << endl;
}
else {
cout << "File contains too many characters." << endl;
}
return In;
};

if (String.Pointer != nullptr)
delete[] String.Pointer;
freed the storage that
String.Pointer[i] = Character; // I get an exception here
was going to use.
Solution:
Don't delete[] the storage. Instead write over it until the storage is full, then allocate a new, larger buffer for storage, copy the old buffer into the new buffer, and then free the old buffer.

Related

Why can't my loop detect \0 symbol in const string?

#include<iostream>
#include<string>
#include<sstream>
#include <typeinfo>
#include<cmath>
#include<vector>
#include <algorithm>
using namespace std;
class Mystring {
char *arr;
public:
Mystring(const char pointer[]) {
int i = 0;
while (pointer[i] != '\0') {
i++;
cout << pointer[i] << endl;
}
arr = new char[i];
i = 0;
while (pointer[i] != '\0') {
arr[i] = pointer[i];
i++;
}
}
friend ostream& operator<<(ostream& out, Mystring& str) {
int i = 0;
while (str.arr[i] != '\0') {
out << str.arr[i];
i++;
}
return out;
}
};
int main() {
Mystring string("Hello, world!");
cout << string << endl;
}
I'm trying to create my own string class. The length of "hello world!" is 13, but the length of arr turns out to be 17. It is filled with some strange chars for some reason I don't understand. When I'm trying to cout string it returns this: Hello, world!¤¤¤¤.
You forgot to add '\0' at the end of your arr[].
Moreover, the size or arrshould be increased to incorporate this \0, as noted in #user7860670's answer.
Moreover, using string as a variable name, in addition to using namespace std;, is confusing at least.
#include<iostream>
#include<string>
#include<sstream>
#include <typeinfo>
#include<cmath>
#include<vector>
#include <algorithm>
//using namespace std;
class Mystring {
char *arr;
public:
Mystring(const char pointer[]) {
int i = 0;
while (pointer[i] != '\0') {
i++;
std::cout << pointer[i] << std::endl;
}
arr = new char[i+1];
i = 0;
while (pointer[i] != '\0') {
arr[i] = pointer[i];
i++;
}
arr[i] = '\0';
}
friend std::ostream& operator<<(std::ostream& out, const Mystring& str) {
int i = 0;
while (str.arr[i] != '\0') {
out << str.arr[i];
i++;
}
return out;
}
};
int main() {
Mystring mstring("Hello, world!");
std::cout << mstring << std::endl;
}
Buffer size required to hold "Hello, world!" (including terminating null) is 14 while you only allocate space for 13 chars and completely omit terminating null. So during iteration inside of operator<< buffer index will go out of bounds which is Undefined Behavior.
You should allocate one extra byte and make sure that buffer ends with terminating null
arr = new char[i + 1];
i = 0;
while (pointer[i] != '\0')
{
arr[i] = pointer[i];
++i;
}
arr[i] = '\0';

Segmentation fault after everything executes-dynamic memory allocation: c++

I am fairly new to dynamic memory allocation and am having trouble. I'm thinking the problem is within my allocation function but I could be wrong. Here is the MyString.cpp file.
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "MyString.h"
using namespace std;
MyString::MyString()
{
m_size = 0;
buffer_allocate(0);
}
MyString::MyString(const char * str)
{
m_size = strlen(str);
buffer_allocate(m_size);
for(int i = 0; i < m_size; i++)
{
m_buffer[i] = str[i];
}
}
MyString::MyString(const MyString & other_myStr)
{
m_size = other_myStr.size();
buffer_allocate(other_myStr.size());
for(int i = 0; i < other_myStr.size(); i++)
{
m_buffer[i] = other_myStr.c_str()[i];
}
}
void MyString::buffer_deallocate()
{
delete[] m_buffer;
m_size = 0;
}
void MyString::buffer_allocate(size_t size)
{
try
{
m_buffer = new char[size];
}
catch(bad_alloc& ex)
{
delete[] m_buffer;
}
}
MyString::~MyString()
{
buffer_deallocate();
}
size_t MyString::size() const
{
return m_size;
}
size_t MyString::length() const
{
return m_size - 1;
}
const char* MyString::c_str() const
{
char * arr = (char*) malloc(m_size + 1);
int i;
for(i = 0; i < m_size; i++)
{
arr[i] = m_buffer[i];
}
arr[i] = '\0';
return arr;
}
bool MyString::operator== (const MyString & other_myStr) const
{
for(int i = 0; (i < m_size) && (i < other_myStr.size()); i++)
{
if(m_buffer[i] != other_myStr.c_str()[i])
{
return false;
}
}
if(m_size != other_myStr.size())
{
return false;
}
return true;
}
MyString & MyString::operator= (const MyString & other_myStr)
{
buffer_deallocate();
buffer_allocate(other_myStr.size());
for(int i = 0; i < other_myStr.size(); i++)
{
m_buffer[i] = other_myStr.c_str()[i];
}
return *this;
}
MyString MyString::operator+ (const MyString & other_myStr) const
{
int length = this->size() + other_myStr.size();
char * temp = (char*)malloc(length);
int j = 0;
for(int i = 0; i < length; i++)
{
if(i < this->size())
{
temp[i] = m_buffer[i];
}
else
{
temp[i] = other_myStr.c_str()[j];
j++;
}
}
MyString rhs = MyString(temp);
return rhs;
}
char & MyString::operator[] (size_t index)
{
return m_buffer[index];
}
const char & MyString::operator[] (size_t index) const
{
return m_buffer[index];
}
std::ostream & operator<<(std::ostream & os, const MyString & myStr)
{
for(int i = 0; i < myStr.size(); i++)
{
os << myStr[i];
}
os << endl;
}
Like I said, the segmentation fault is happening after the entire program is being executed so my guess is that there is some memory leak issue. I appreciate the help in advance.
And here is the main function:
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include "MyString.h"
using namespace std;
int main(void)
{
MyString dft;
if(dft.size() == 0)
{
cout << "Successful Default c-tor" << endl;
}
MyString param("Successful Parameter c-tor");
MyString copy(dft);
cout << param;
MyString ms_size_length("Size and length test:");
cout << ms_size_length;
cout << "Size of MyString: " << ms_size_length.size() << endl;
cout << "Length of MyString: " << ms_size_length.length() << endl;
MyString ms_toCstring("C-String equivalent successfully obtained!");
cout << ms_toCstring.c_str() << endl;
MyString ms_same1("The same"), ms_same2("The same");
if (ms_same1==ms_same2)
{
cout << "Same success" << endl;
}
MyString ms_different("The same (NOT)");
if (!(ms_same1==ms_different))
{
cout << "Different success" << endl;
}
MyString ms_assign("Before assignment");
ms_assign = MyString("After performing assignment");
MyString ms_append1("The first part");
MyString ms_append2(" and the second");
MyString ms_concat = ms_append1 + ms_append2;
cout << ms_concat;
MyString ms_access("Access successful (NOT)");
ms_access[17] = 0;
cout << ms_access;
}
One problem that I noticed is:
m_size = strlen(str);
buffer_allocate(m_size);
That allocates one less than the number of characters you need. As a consequence, you end up not copying the terminating null character to the object's m_buffer.
I suggest changing the constructor to:
MyString::MyString(const char * str)
{
m_size = strlen(str)+1;
buffer_allocate(m_size);
strcpy(m_buffer, str);
}
PS I did not look for other problems in your code. There may be more, or none.

Assertion `str' failed

I am new bee for c++ . I got follow error when I override operator+ .
ConsoleApplication1.out: /root/projects/ConsoleApplication1/sdstring.cpp:43: static sdstring::size_t sdstring::strlen(const char*): Assertion `str' failed.
This is my test code!
sdstring sd1(NULL);
cout << "sd1:" << sd1 << endl;
sdstring sd2("sd2");
cout << "sd2:" << sd2 << endl;
sdstring sd3;
cin >> sd3;
cout << "sd3:" << sd3 << endl;
sd3 +=sd2 ;
cout << "sd3:" << sd3 << endl;
sdstring sd4 =sd3+sd1;
cout << "sd4:" << sd2 << endl;
sd1 = sd2 + sd1;
cout << "sd1:" << sd1 << endl;
cout << "sd3==sd2:" << (sd3 == sd2)<<endl;
Error happened in This line .
sdstring sd4 =sd3+sd1;
This is my sdstring.cpp file.
#include "sdstring.h"
#include <assert.h>
sdstring::sdstring(const char *str) {
if (!str) {
datas = new char[1];
datas[0] = '\0';
}
else {
datas = new char[strlen(str)+1];
strcpy(datas, str);
}
}
sdstring::sdstring(const sdstring& str) {
datas = new char[strlen(str.datas) + 1];
strcpy(datas, str.datas);
}
sdstring& sdstring::operator+(const sdstring& str)const {
sdstring result(NULL);
size_t total_size = getlen() + str.getlen();
result.datas = new char[total_size + 1];
strcpy(result.datas, datas);
strcat(result.datas, str.datas);
return result;
}
bool sdstring::operator==(const sdstring& str)const {
return strcmp(datas, str.datas) == 0;
}
sdstring& sdstring::operator=(const sdstring& str) {
if (this == &str)
return *this;
delete[] datas;
datas = new char[str.getlen() + 1];
strcpy(datas, str.datas);
return *this;
}
sdstring::size_t sdstring::strlen(const char* str) {
assert(str);
size_t len = 0;
while ('\0' != *str++)
len++;
return len;
}
char* sdstring::strcpy( char* des, const char* src){
assert(des&& src);
char* temp = des;
while ('\0' != (*des++ = *src++));
return temp;
}
int sdstring::strcmp(const char* fir, const char* sec) {
assert(fir && sec);
while (*fir == *sec)
{
if (*fir == '\0') {
return 0;
}
++fir;
++sec;
}
return *fir - *sec;
}
char* sdstring::strcat(char* des,const char* src) {
char* temp = des;
while ('\0' != *des)
{
des++;
}
while ('\0' != (*des++ = *src++));
return temp;
}
sdstring::~sdstring()
{
if (datas)
{
delete[] datas;
datas = nullptr;
}
}
char& sdstring::operator[](const unsigned int position)const
{
return position < getlen() ? datas[position] : datas[position-1];
}
sdstring& sdstring::operator+=(const sdstring& str)
{
size_t total_size = getlen() + str.getlen();
if (total_size != getlen()) {
char* temp = datas;
datas = new char[total_size + 1];
strcpy(datas,temp);
strcat(datas, str.datas);
delete[] temp;
}
return *this;
}
ostream& operator<<(ostream& os, const sdstring& str)
{
os << str.datas;
return os;
}
istream& operator>>(istream& is, sdstring& str)
{
char* cache = new char[1024];
is >> cache;
delete[]str.datas;
str.datas = new char[sdstring::strlen(cache)];
sdstring::strcpy(str.datas, cache);
delete[]cache;
return is;
}
Who can help me , Thanks for first!
There are several things wrong with your code. However the operator + is wrong in that it is returning a reference to a local variable, which is undefined behavior.
sdstring& sdstring::operator+(const sdstring& str)const
{
sdstring result(NULL);
//..
return result; // Undefined behavior.
}
operator + should be returning a brand new object, not a reference to an object.
sdstring sdstring::operator+(const sdstring& str)const // <-- Note the return value is sdstring
{
sdstring result(NULL);
//..
return result;
}
The other issues with your code:
1) The operator= destroys the memory using delete[] datas; before calling new[] to allocate memory for the new string. If new[] throws an exception, the sdstring object would be corrupted since the data has been destroyed and you can't go back and reset the string with the old data. Use the copy / swap idiom to prevent this from happening.
2) You should store the length of the string in a member variable instead of calling strlen every time you want to know the length of the string. The strlen is slow in that it has to loop to count every single character to determine where the terminating '\0' character is located. Instead of that, just store the length of the string once and keep using that value.
3) Instead of writing your own strlen and strcmp functions, use the library functions strlen and strcmp. Your versions are not optimized, unlike the library versions.
4) operator + can be written in terms of operator +=. operator + should be written very simply as:
sdstring sdstring::operator + (const sdstring& rhs)
{
return sdstring(*this) += rhs;
}

Read Access Violation _First was nullPtr

I have a default constructor, copy constructor, destructor, assignment operator, length, and string functions. When I call the copy constructor and try to print the value of the new char*, I get a Read Access Violation _First was nullptr. The debugger shows iosfwd code and breaks at the error, but I have no clue what this means. Any help would be awesome.
This is where the debugger shows the error.
static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
{ // find length of null-terminated string
return (*_First == 0 ? 0 // <- this line
: _CSTD strlen(_First));
}
These are my functions (also not that we were not allowed to use STRCPY)
MyString::MyString() { //default constructor
string = new char[6];
int i = 0;
for (i; i < strlen(string); i++) {
string[i] = NULL;
}
string[i] = '\0';
}
MyString::MyString(const MyString &s) { //copy constructor
char* string = new char[strlen(s.string) + 1];
int i = 0;
for (i; i < strlen(s.string); i++) {
string[i] = s.string[i];
}
string[i] = '\0';
}
MyString::~MyString() { //destructor
delete[] string;
string = NULL;
}
MyString& MyString::operator=(const MyString& s) { //assignment operator
char* temp = new char[strlen(s.string) + 1];
int i = 0;
for (i; i < strlen(s.string); i++) {
temp[i] = s.string[i];
}
temp [i] = '\0';
delete[] string;
string = temp;
return *this;
}
size_t MyString::length() const { //length of string
return strlen(string);
}
char* MyString::cString() { //string
return string;
}
int main(int argc, const char * argv[]){
MyString s;
std::cout << "Empty: '" << s.cString() << "'\n";
s = "hello";
std::cout << "After operator=: '" << s.cString() << "'\n";
{
MyString t(s);
std::cout << "After copy: '" << t.cString() << "'\n";
s = t;
}
}
This line in your copy constructor
char* string = new char[strlen(s.string) + 1];
Creates a new local variable called string which means that your member variable called string is never assigned a value.
Remove the char *

Program crashes due to undefined behavior

So I'm writing a program that creates a library for a collection of CDs and displays them. My program compiles but crashes whenever I write an array of pointers to songs from a file into structs contained within an array shown here:
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
I think it's due to undefined behavior, here's the .cpp file that this is happening in.
#include <iostream>
#include "CDs.h"
#include "CD.h"
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
//Creates a collection of CDs
CDs* createCDs(const char* file_name)
{
//Declare variables and allocate memory
int max_cds = 50;
CDs* collection = new CDs;
collection->max_cds = max_cds;
CD** cd_array = new CD*[max_cds];
int num;
int sentinel = 0;
String* word;
string line;
CD* cd;
const char* sub;
String* length;
String* title;
//Open .txt file
ifstream infile;
infile.open(file_name);
if (infile.is_open())
{
while (infile.good())
{
for (int i = 0; i < max_cds; i++)
{
//Get the artist from .txt file
cd = cd_array[i];
getline (infile, line);
sub = line.c_str();
word = createString(sub); //Create string from infile line
cd->artist = word;
destroyString(word);
//Get the Title of the album from file
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cd->title = word;
destroyString(word);
//Get the Year of the album from file
infile >> num;
cd->year = num;
//Get the Rating
infile >> num;
cd->rating = num;
//Get number of tracks
int num_songs;
infile >> cd->num_tracks;
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cout << "SHIT" << endl;
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
cd_array[i] = cd;
sentinel++;
}
}
}
else
{
cout << "file did not open";
}
collection->cd_array = cd_array;
collection->num_cds = sentinel;
collection->max_cds = max_cds;
return collection;
}
I have no idea what to do to make this run, If someone could help that would be amazing.
edit - I didn't give the .cpp that is included and has some of the functions used
#include <iostream>
#include <cstring>
#include "String.h"
using namespace std;
//Function that creates a string
String* createString(const char* char_array)
{
//Allocate memory for a pointer to String struct
//String* string;
String* string = new String;
//Write the char_array to String struct
int length = strlen(char_array);
char array[30];
for (int i = 0; i <= length; i++)
{
array[i] = char_array[i];
string->array[i] = array[i];
}
return string;
}
//Function that displays the string
void displayString(String* str)
{
for (int i = 0; i < strlen(str->array); i++)
{
cout << str->array[i];
}
cout << endl;
}
//Function that destroys the string
void destroyString(String* str)
{
delete str;
str = NULL;
}
int find(String* str, char delimiter, int start)
{
for (int i = start; i <= strlen(str->array); i++)
{
if (str->array[i] == delimiter)
{
return i;
}
}
cout << "No occurences of delimiter were found" << endl;
return -1;
}
String* substr(String* str, int start, int end)
{
String* new_str = new String;
int count = 0;
for (int i = start + 1; i < end - 1; i++)
{
new_str->array[count] = str->array[i];
count++;
}
return new_str;
}
void compare(String* str1, String* str2)
{
if (str1->array < str2->array)
{
cout << str1->array << " is less than " << str2->array << endl;
}
if (str1 > str2)
{
cout << str2->array <<" is less than " << str1->array << endl;
}
if (str1 == str2)
{
cout << "The strings are equal" << endl;
}
}
You never allocate memory for the effective CD. You just allocate an array of pointers to CDs (cd_array). This means you have an array of pointers, pointing to unkown memory locations.
The best way to ensure no such bad access is possible, is to not dynamically allocate memory. Just use CD cd_array[max_cds] and work with that. (Use call by reference, if you need to pass this to a function.)
You need to add the following lines:
//Get the artist from .txt file
cd_array[i] = new CD;
cd = cd_array[i];
.....
You should de-allocate the memory once finished using them
for(...)
delete cd_array[i];
delete []cd_array;