Exception thrown at 0x0F640E09 (ucrtbased.dll) in

2019-09-21 17:13发布

问题:

I just compiled this code, and it showed me this error:
Exception thrown at 0x0F640E09 (ucrtbased.dll) in ConsoleApplication5.exe: 0xC0000005: Access violation writing location 0x014C3000. I literally have no idea what this error means as I've just been using C++ for a couple months, and I've also tried looking on any other websites to look for help, but I didn't find any.

For this code, I'm only allowed to use the c-string functions and the <cstring> library. I cannot use the string object or include the library. I can also use helper methods/functions.

#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;

class MyString {
public:

    //default constructor
    MyString();

    MyString(char* chars);

    //copy constructor
    MyString(const MyString &);

    int length() const;

    //destructor
    ~MyString();

    //operator overloads
    char& operator[](int index);
    friend MyString operator+(const MyString& newWord, const MyString& newWord2);
    MyString& operator+=(const MyString& newWord);
    friend ostream& operator<<(ostream& newWord, const MyString& newWord2);
    friend istream& operator >> (istream& newWord, MyString& newWord2);
    friend bool operator==(const MyString& newWord, const MyString& newWord2);
    friend bool operator!=(const MyString& newWord, const MyString& newWord2);
    friend bool operator<(const MyString& newWord, const MyString& newWord2);
    friend bool operator<=(const MyString& newWord, const MyString& newWord2);
    friend bool operator>(const MyString& newWord, const MyString& newWord2);
    friend bool operator>=(const MyString& newWord, const MyString& newWord2);

private:
    char* value;
    int size;
};

//default constructor
MyString::MyString() {

    value = 0;
    size = 0;
}

//copy constructor
MyString::MyString(const MyString& newWord) {

    //perform a deep copy to copy each of the value to a new memory
    size = newWord.size;
    value = new char[size];

    for (int ii = 0; ii < size; ii++) {
        value[ii] = newWord.value[ii];
    }
}

//constructor with an argument
MyString::MyString(char* chars) {

    size = strlen(chars);
    value = new char[size];
    for (int i = 0; i < size; i++) {
        value[i] = chars[i];
    }

}

//find length
int MyString::length() const {

    return size;
}

//find the value of each index
char& MyString::operator[](int index) {

    return value[index];
}

//operator + (concatenate)
MyString operator+(const MyString& newWord, const MyString& newWord2) {

    MyString concatenated;
    concatenated = strcat(newWord.value, newWord.value);
    return concatenated;

}

//operator += (append)
MyString& MyString::operator+=(const MyString& newWord) {

    char * newMemory = value;
    value = new char[strlen(value) + newWord.length() + 1];
    strcpy(value, newMemory);
    strcat(value, newWord.value);
    if (size != 0)
    {
        delete[] newMemory;
    }
    size = strlen(value);
    return *this;
}

//ostream operator
ostream& operator<<(ostream& newWord, const MyString& newWord2) {

    newWord << newWord2.value;
    return newWord;
}


//istream operator
istream& operator >> (istream& newWord, MyString& newWord2) {

    const int MAX = 100;
    char* ptr = new char[MAX];
    newWord >> ptr;
    newWord2 = MyString(ptr);
    delete ptr;
    return newWord;
}

//all boolean operators
bool operator==(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value == newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator!=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value != newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator<(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value < newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator<=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value <= newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator>(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value > newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator>=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value >= newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

//destructor to release memory
MyString::~MyString() {
    delete[] value;
}

void test_copy_and_destructor(MyString S) {
    cout << "test: copy constructor and destructor calls: " << endl;
    MyString temp = S;
    cout << "temp inside function test_copy_and_destructor: " << temp << endl;
}

int main() {

    MyString st1("abc abc");
    MyString st2("9fgth");

    cout << "Copy constructor , << operator" << endl;

    MyString  st3(st1);

    cout << "st3: " << st3 << endl;

    test_copy_and_destructor(st2);

    MyString  st4;

    cout << "operator + " << endl;

    st4 = st3 + st2;

    cout << "st4: " << st4 << endl;

    cout << "st1 + st2: " << (st1 + st2) << endl;

    cout << "operators  [ ] " << endl;

    for (int i = 0; i < st2.length(); i++)
        cout << st2[i] << " ";

    cout << endl;

    cout << "operators  += , ==, != " << endl;

    st2 += st1;

    if (st3 == st1)
        cout << "st3 and st1 are identical " << endl;
    else cout << "st3 and st1 are not identical " << endl;

    if (st2 != st1)
        cout << "st2 and st1 are not identical " << endl;
    else cout << "st2 and st1 are identical " << endl;

    cout << "operators  < , <=, >, >= " << endl;

    if (st2 < st1)
        cout << "st2 < st1 " << endl;
    else cout << "st2 is not less than st1 " << endl;

    if (st1 <= st2)
        cout << "st1 <= st2 " << endl;
    else cout << "st1 is not less than or equal to st2 " << endl;

    if (st1 > st2)
        cout << "st1 > st2 " << endl;
    else cout << "not (st1 >  st2) " << endl;

    if (st1 >= st2)
        cout << "st1 >= st2 " << endl;
    else cout << "not (st1 >=  st2) " << endl;

    cout << "operator >> " << endl;

    //Open the data file
    ifstream input("A9_input.txt");
    if (input.fail()) {
        cout << "unable to open input file A9_input.txt, Exiting..... ";
        system("pause");
        return 0;
    }
    MyString temp1;
    MyString temp2("aaa");
    input >> temp1;
    input >> temp2;
    cout << "first element of input file: " << temp1 << endl;
    cout << "second element of input file: " << temp2 << endl;
    input.close();

    cout << "MyString says farewell....." << endl;
    system("pause");
    return 0;
}

回答1:

You error most likely should be on following code:

st4 = st3 + st2; # note that you initialize st4 with type MyString but inside operator+ you assign a char[] to MyString. Just letting you know since you dont have a operator= overloaded function 

calls:

MyString operator+(const MyString& newWord, const MyString& newWord2) {

    MyString concatenated;
    concatenated = strcat(newWord.value, newWord.value); # you have an mistake here, second parameter should be newWord2.value
    return concatenated;

}

You are making an assumption that your newWord.value holds enough space to hold newWord.value and newWord2.value. but it is not you inisialized it on your constructor to be newWord.value so you are basically writng in to a region that violate memory access. What you want to do is make newWord big enough to hold both strings.

reference to strcat : http://www.cplusplus.com/reference/cstring/strcat/



回答2:

Your operator + is writing past the allocated memory (buffer overflow). You can easily change it to the very simple:

MyString operator +(const MyString& newWord, const MyString& newWord2) {
    MyString concatenated;
    return concatenated += newWord2;
}

then it even doesn't need to be a friend of the class.

Also the operator += is wrong, because your strings are not created NULL terminated initially, so in the fact you shouldn't use strlen(), strcpy() and strcat() at all, because you are then concatenating arbitrary memory together (reading past allocated memory can also segfault). So you should make your mind whether you want the strings NULL terminated (and used as such) or not.

The operator += is also not defined very effectively anyway, more clean and effective could be for example:

MyString& MyString::operator+=(const MyString& newWord) {
    size_t newSize = size + newWord.size;
    char * newValue = new char[newSize /* + 1 */]; // not null terminated, but cannot be printed easily then
                                          // or make the string initially null terminated and then allocate +1 and null terminate then
    memcpy(newValue, value, size);
    memcpy(newValue + size, newWord.value, newWord.size /* + 1 */);
    delete[] value;
    value = newValue;
    size = newSize;
    return *this;
}

See? No use of strlen() which traverses the strings (not null terminated in your case), because you know the size of the string anyway. You can also use memcpy() in the constructors instead of the for (int i = 0; i < size; i++) loops. Or strcpy() and make the string null-terminated (but even then memcpy() can be used as it is faster - does not test for the '\0' on every character copied).

The operators ==, != do not seem very correct either, as only the pointers are compared (so the string will only ever be equal to itself, but not to other string with the same characters stored in value).

Furthermore, as the initial strings are not null terminated, the operator << will not work correctly either (will print out arbitrary memory past the string). In general, I would recommend to make the string value always null terminated to avoid some of the issues.

And finally, you definitely need to define operator =, because for now you are using the default one which does a shallow copy, so with this code you will have double-free at destruction of st4 (and any other string assigned with =). Note that implementing the operator = correctly is also tricky - beware of the self-assignment scenario.



回答3:

There are other issues with your code, most dealing with your comparison operators.

Your operator < and operator== for MyString are incorrect. To compare c-style strings, you use strcmp, not ==. Your comparison operators instead is comparing pointer values, not the data that is being pointed to.


The second issue is that all you need to do is fully implement operator < and operator ==, as all of the other comparison operators can be implemented in terms of these functions.

Putting this all together, the implementation of your class should look something like this:

#include <cstring>
//...     
class MyString {
public:
    //...    
    friend bool operator==(const MyString& newWord, const MyString& newWord2);
    friend bool operator!=(const MyString& newWord, const MyString& newWord2);
    friend bool operator<(const MyString& newWord, const MyString& newWord2);
    friend bool operator<=(const MyString& newWord, const MyString& newWord2);
    friend bool operator>(const MyString& newWord, const MyString& newWord2);
    friend bool operator>=(const MyString& newWord, const MyString& newWord2);

private:
    char* value;
    int size;
};

bool operator==(const MyString& newWord, const MyString& newWord2) 
{ return strcmp(newWord.value, newWord2.value) == 0; } 

bool operator<(const MyString& newWord, const MyString& newWord2) 
{ return strcmp(newWord.value, newWord2.value) == -1; }

bool operator!=(const MyString& newWord, const MyString& newWord2)
{ return !(newWord == newWord2); }

bool operator<=(const MyString& newWord, const MyString& newWord2)
{ return !(newWord2 < newWord); }   

bool operator> (const MyString& newWord, const MyString& newWord2)
{ return newWord2 < newWord; }

bool operator>=(const MyString& newWord, const MyString& newWord2)
{ return !(newWord < newWord2); }

Note that the operators use the < and == to implement the other operators.


The third issue is that you're missing an assignment operator

MyString& operator=(const MyString&)

Without this function, you cannot assign MyString objects to each other without corrupting memory.