代码在Linux上编译和运行,在Windows上因堆损坏而崩溃

时间:2019-06-15 00:50:13

标签: c++ linux windows g++ runtime-error

我正在使用PowerShell测试Microsoft'cl'编译器,并且我想尝试为自定义MyString类编译并运行旧的作业分配。有问题的作业以前已经编译过并可以在Linux上使用g ++运行,没有任何问题(并且我认为这应该是正确的,因为我获得100%的作业)。但是,当我尝试在Windows上使用cl甚至MinGW在Windows上编译此代码时,它编译时没有错误,但在运行时崩溃。

我尝试编译所有其他旧任务,它们在Windows上运行良好(使用MinGW或cl)。我尝试对cl使用/ Zi选项,并运行了Visual Studio调试器,该调试器告诉我我正在引起堆损坏错误。我尝试重新编写我认为可能是问题的部分代码,但我根本无法弄清楚。

我怀疑问题可能出在我如何进行操作符重载;如果这不是问题,我将发布其余代码。

MyString& MyString::operator+=(const char rhs)
{   
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += 1;    //set new length (addition is single char)
    string = new char[length];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    string[length - 1] = rhs;   //concatenate return string with added char 
    return *this;   //return this object as reference
}

MyString& MyString::operator+=(const char* rhs)
{
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += strlen(rhs);  //set new length (addition is c-string)
    string = new char[length];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    strcat(string, rhs);    //concatenate return string with added c-string 
    return *this;   //return this object as reference
}

MyString& MyString::operator+=(const MyString& rhs)
{
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += rhs.length;   //set new length (addition is MyString)
    string = new char[length];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    strcat(string, rhs.string); //concatenate return string with added MyString
    return *this;   //return this object as reference
}

Visual Studio一直停在的另一个位置是我教授的头文件的一部分:

//casting operator: an operator to cast MyString to string type.
//This is going to be used in main() function, in order to grade your assignment.
    inline operator std::string() const
    {
        std::stringstream os;
        for(int i=0; i<length; i++)
            os << string[i];
        std::string str = os.str();
        return str;
    }

在Linux上运行良好,在Windows上也无法运行(即使同时通过g ++成功编译)。

EDIT2: 对于不包括我的所有信息,我深表歉意。基于提交过程中的一些文字,我对此感到不应该。

我遵循了jww的建议,并重做了我的代码以说明c字符串中的空终止符。我仍然遇到同样的问题。

要为MinGW或g ++进行编译,请使用注释头中的说明。 使用cl进行编译:

cl /TP /utf-8 /EHa /Fetestmystring mystring.cxx testmystring.cxx

或用于VS调试:

cl /TP /utf-8 /EHa /Zi /Fetestmystring mystring.cxx testmystring.cxx

这是我的“ mystring.cxx”

// Description: This is the function definition file for a custom
//  string class.  
//
// To compile, use the following:
//
//   g++ -ansi -pedantic -Wall mystring.cxx testmystring.cxx -o testmystring
//
// To run, use the following:
//
//   ./testmystring
//
// Acknowledgements:
// 1. I used Dr. ####'s startup files.
// 2. I referred to https://en.cppreference.com/w/ to find some of the functions
//  that I ended up using.
//=====================================================================
#include <iostream>
#include <assert.h>
#include <string.h>
#include "mystring.h"

MyString::MyString()
{
    length = 0; //default constructor, initiate to '0' and 'NULL'
    string = NULL;
}

MyString::MyString(const char src)
{
    length = 1; //set length (char)
    string = new char[length + 1];  //allocate memory for string
    string[0] = src;    //set string
    string[1] = '\0';
}

MyString::MyString(const char* src)
{
    length = strlen(src);   //set length (c-string)
    string = new char[length + 1];  //allocate memory for string
    strcpy(string, src);    //set string via copy
    string[length] = '\0';
}

MyString::MyString(const MyString& src)
{
    length = src.length;    //copy constructor; copy length
    string = new char[length + 1];  //allocate memory of correct length
    strcpy(string, src.string); //deep copy the string
    string[length] = '\0';
}

MyString::~MyString()
{
    delete [] string;   //destructor, safely delete allocated memory
    string = NULL;
}

int MyString::GetLength() const
{
    return length;  //simple getter, nothing complicated
}

char MyString::GetCharAt(int index) const
{
    return string[index];   //simple getter, could add out-of-bounds error checking
}

void MyString::SetCharAt(int index, char ch) const
{
    string[index] = ch; //simple setter, could add out-of-bounds error checking
}

MyString& MyString::operator= (const char rhs)
{
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length = 1; //set length (input is single char)
    string = new char[length + 1];  //allocate memory for string
    string[0] = rhs;    //initiate string
    string[1] = '\0';
    return *this;   //return this object as reference
}

MyString& MyString::operator= (const char* rhs)
{
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length = strlen(rhs);   //set length (input is c-string)
    string = new char[length + 1];  //allocate memory for string
    strcpy(string, rhs);    //initiate string
    string[length] = '\0';
    return *this;   //return this object as reference
}

MyString& MyString::operator= (const MyString& rhs)
{
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length = rhs.length;    //copy length
    string = new char[length + 1];  //allocate new string of correct length
    strcpy(string, rhs.string); //deep copy implementation
    string[length] = '\0';
    return *this;   //return this object as reference
}

MyString MyString::operator+ (const char rhs) const
{
    MyString ret;   //create string object for returning
    ret.length = length + 1;    //initiate return string length (current + 1)
    ret.string = new char[ret.length + 1];  //allocate return string memory
    strcpy(ret.string, string); //set initial return string value
    ret.string[ret.length - 1] = rhs;   //concatenate return string with added char
    ret.string[ret.length] = '\0';
    return ret; //return addition result
}

MyString MyString::operator+ (const char* rhs) const
{
    MyString ret;   //create string object for returning
    ret.length = length + strlen(rhs);  //initiate return string length (current + new)
    ret.string = new char[ret.length + 1];  //allocate return string memory
    strcpy(ret.string, string); //set initial return string value
    strcat(ret.string, rhs);    //concatenate return string with added c-string
    ret.string[ret.length] = '\0';
    return ret; //return addition result
}

MyString MyString::operator+ (const MyString& rhs) const
{
    MyString ret;   //create string object for returning
    ret.length = length + rhs.length;   //initiate return string length (current + new)
    ret.string = new char[ret.length + 1];  //allocate return string memory
    strcpy(ret.string, string); //set initial return string value
    strcat(ret.string, rhs.string); //concatenate return string with added MyString
    ret.string[ret.length] = '\0';
    return ret; //return addition result
}

MyString& MyString::operator+=(const char rhs)
{   
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += 1;    //set new length (addition is single char)
    string = new char[length + 1];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    string[length - 1] = rhs;   //concatenate return string with added char 
    string[length] = '\0';
    return *this;   //return this object as reference
}

MyString& MyString::operator+=(const char* rhs)
{
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += strlen(rhs);  //set new length (addition is c-string)
    string = new char[length + 1];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    strcat(string, rhs);    //concatenate return string with added c-string 
    string[length] = '\0';
    return *this;   //return this object as reference
}

MyString& MyString::operator+=(const MyString& rhs)
{
    MyString temp(*this);   //create temporary MyString object from 'this'
    delete [] string;   //clear string memory if it exists
    string = NULL;
    length += rhs.length;   //set new length (addition is MyString)
    string = new char[length + 1];  //allocate new memory for string
    strcpy(string, temp.string);    //set initial return string value
    strcat(string, rhs.string); //concatenate return string with added MyString
    string[length] = '\0';
    return *this;   //return this object as reference
}

bool MyString::operator==(const MyString& rhs) const
{
    if(rhs.length != length)
        return false;   //if string length's are != then return false and break
    for(int i = 0; i < length; i++) //loop through string
        if(rhs.string[i] != string[i])  //compare each char
            return false;   //if chars != then return false and break
    return true;    //if you got to here, strings are ==, so return true
}

bool MyString::operator==(const char* rhs) const
{
    if(static_cast<int>(strlen(rhs)) != length) //static cast to get rid of signed/unsigned warning
        return false;   //if string length's are != then return false and break
    for(int i = 0; i < length; i++) //loop through string
        if(rhs[i] != string[i]) //compare each char
            return false;   //if chars != then return false and break
    return true;    //if you got to here, strings are ==, so return true
}

bool MyString::operator!=(const MyString& rhs) const
{
    if(rhs.length != length)
        return true;    //if string length's are != then return true and break
    for(int i = 0; i < length; i++) //loop through string
        if(rhs.string[i] != string[i])  //compare each char
            return true;    //if chars != then return true and break
    return false;   //if you got to here, strings are ==, so return false
}

bool MyString::operator!=(const char* rhs) const
{
    if(static_cast<int>(strlen(rhs)) != length) //static cast to get rid of signed/unsigned warning
        return true;    //if string length's are != then return true and break
    for(int i = 0; i < length; i++) //loop through string
        if(rhs[i] != string[i]) //compare each char
            return true;    //if chars != then return true and break
    return false;   //if you got to here, strings are ==, so return false
}

std::ostream& operator<< (std::ostream& os, const MyString& str)
{
    return os << str.string;    //pass string through ostream and return as reference (for loop as alternative?)
}

std::istream& operator>> (std::istream& is, MyString& str)
{
    char temp[4096];    //temporary, arbitrarily sized array (would prefer a better method)
    delete [] str.string;   //clear string memory if it exists
    str.string = NULL;
    is.read(temp, sizeof temp); //read input into local temp array
    str.length = is.gcount();   //set string length to size of input
    str.string = new char[str.length + 1];  //create new string of correct length   
    strcpy(str.string, temp);    //move input from temp to string
    str.string[str.length] = '\0';
    return is;  //return istream as reference
}

我的教授提供的“ mystring.h”

*  Description:                                                         *
*                                                                       *
*  This is a header file for MyString class.                            *
*  Do not modify this file. Implement methods in MyString.cxx.          *
*                                                                       *
*  Please report any bug to ####(professor's email, hidden for privacy) *
*************************************************************************/

#ifndef __mystring_h__
#define __mystring_h__

#include <iostream>
#include <string>
#include <sstream>
#include <assert.h>

using namespace std;

class MyString
{
private:
    int   length;   // length of a string
    char* string;   // string pointer. Its size must be length.
public:
    // casting operator: an operator to cast MyString to string type.
    //                   This is going to be used in main() function, in order to grade your assignment.
    inline operator std::string() const
    {
        std::stringstream os;
        for(int i=0; i<length; i++)
            os << string[i];
        std::string str = os.str();
        return str;
    }
    // index operator []: an operator that allows array like operation. ( ex: a[3] )
    //                    This is going to be used for test 08 in main() function, in order to grade your assignment.
    char operator[] (int index)
    {
        if(index < 0      ) throw "out of index in operator[]";
        if(index >= length) throw "out of index in operator[]";
        return string[index];
    }
public:
    MyString();
    MyString(const char src);               // create a string from a char
    MyString(const char* src);              // create a string from C-string
    MyString(const MyString& src);          // copy constructor
    ~MyString();                            // destructor

    int GetLength() const;                      // getter
    char GetCharAt(int index) const;            // getter
    void SetCharAt(int index, char ch) const;   // setter

    // assignment operator
    MyString& operator= (const char rhs);           // operator =
    MyString& operator= (const char* rhs);          // operator =
    MyString& operator= (const MyString& rhs);      // operator =

    MyString  operator+ (const char rhs) const;     // operator +
    MyString  operator+ (const char* rhs) const;    // operator +
    MyString  operator+ (const MyString& rhs) const;// operator +

    MyString& operator+=(const char rhs);           // operator +=
    MyString& operator+=(const char* rhs);          // operator +=
    MyString& operator+=(const MyString& rhs);      // operator +=

    // equality/inequality operators
    bool operator==(const MyString& rhs) const;     // operator ==
    bool operator==(const char* rhs) const;         // operator ==
    bool operator!=(const MyString& rhs) const;     // operator !=
    bool operator!=(const char* rhs) const;         // operator !=

    // stream insertion/extraction operators as friend
    friend std::ostream& operator<< (std::ostream& os, const MyString& str);
    friend std::istream& operator>> (std::istream& is, MyString& str);
};

#endif

我的教授提供的“ testmystring.cxx”

*  Description:                                                         *
*                                                                       *
*  This is a test program for class MyString.                           *
*  Do not modify this file.                                             *
*                                                                       *
*  Please report any bug to ##### (Proff's email)                       *
*************************************************************************/

#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <cmath>
#include <string>
#include <string.h>
#include "mystring.h"

using namespace std;

template<typename T>
void TestOutput(int& num_tests, int& num_success, T value, T expect, string testname)
{
    num_tests++;
    cout << endl << testname << endl;
    cout << "  result: " << value  << endl;
    cout << "  expect: " << expect << endl;

    if (value == expect)
    {
        num_success++;
        cout << "  test success" << endl;
    }
    else
    {
        cout << "  test failed !!!!!" << endl;
    }
}

int main()
{
    int num_tests = 0;      // total number of tests
    int num_success = 0;    // number of tests succeeded

    try
    {
        // test constructors
        MyString t01;                    TestOutput<string>(num_tests, num_success, (string)t01, ""         , "test 01 - default constructor");
        MyString t02('c');               TestOutput<string>(num_tests, num_success, (string)t02, "c"        , "test 02 - constructor: MyString(const char)");
        MyString t03("abc");             TestOutput<string>(num_tests, num_success, (string)t03, "abc"      , "test 03 - constructor: MyString(const char*)");
        MyString t04(t03);               TestOutput<string>(num_tests, num_success, (string)t04, "abc"      , "test 04 - copy constructor");

        // test getters and setters
                                        TestOutput<int   >(num_tests, num_success,         t04.GetLength()  , 3     , "test 05 - GetLength()");
                                        TestOutput<char  >(num_tests, num_success,         t04.GetCharAt(0) , 'a'   , "test 06 - GetCharAt()");
                                        TestOutput<char  >(num_tests, num_success,         t04.GetCharAt(1) , 'b'   , "test 07 - GetCharAt()");
                                        TestOutput<char  >(num_tests, num_success,         t04[2]           , 'c'   , "test 08 - operator[] (int)");
        t04.SetCharAt(2, 'x');          TestOutput<string>(num_tests, num_success, (string)t04              , "abx" , "test 09 - SetCharAt()");

        // operators
        MyString t05, t06;
        t05 = 's';                      TestOutput<string>(num_tests, num_success, (string)t05, "s"     , "test 10 - operator=(const char)");
        t05 = "qwert";                  TestOutput<string>(num_tests, num_success, (string)t05, "qwert" , "test 11 - operator=(const char*)");
        t06 = t05 = " zxc";             TestOutput<string>(num_tests, num_success, (string)t05, " zxc"  , "test 12 - operator=(const char*)");
                                        TestOutput<string>(num_tests, num_success, (string)t06, " zxc"  , "test 13 - operator=(const MyString&)");

        MyString t07;
        t07 = t03 + '_';                TestOutput<string>(num_tests, num_success, (string)t07, "abc_"      , "test 14 - operator+(const char) const");
        t07 = t03 + "_1234";            TestOutput<string>(num_tests, num_success, (string)t07, "abc_1234"  , "test 15 - operator+(const char*) const");
        t07 = t03 + t05;                TestOutput<string>(num_tests, num_success, (string)t07, "abc zxc"   , "test 16 - operator+(const MyString&) const");

        t07 += '#';                     TestOutput<string>(num_tests, num_success, (string)t07, "abc zxc#"                  , "test 17 - operator+=(const char)");
        t07 += "hjkl";                  TestOutput<string>(num_tests, num_success, (string)t07, "abc zxc#hjkl"              , "test 18 - operator+=(const char*)");
        t07 += t07;                     TestOutput<string>(num_tests, num_success, (string)t07, "abc zxc#hjklabc zxc#hjkl"  , "test 19 - operator+=(const MyString&)");

        MyString t08="siejfin";
        MyString t09="siejfin";
        MyString t10="siejfi_";
        MyString t11="siejfin ";
                                        TestOutput<bool  >(num_tests, num_success, t08 == t09  , true , "test 20 - operator==(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t08 == t10  , false, "test 21 - operator==(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t08 == t11  , false, "test 22 - operator==(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t03 == "abc", true , "test 23 - operator==(const char*) const");
                                        TestOutput<bool  >(num_tests, num_success, t03 == "ab" , false, "test 24 - operator==(const char*) const");

                                        TestOutput<bool  >(num_tests, num_success, t08 != t09  , false, "test 25 - operator!=(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t08 != t10  , true , "test 26 - operator!=(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t08 != t11  , true , "test 27 - operator!=(const MyString&) const");
                                        TestOutput<bool  >(num_tests, num_success, t03 != "abc", false, "test 28 - operator!=(const char*) const");

        MyString t12("test-stream");
        {
            // save data of t12 to a file
            ofstream infile;
            infile.open("./testMyString.data");
            infile << t12;
            infile.close();
            // read MyString from the file
            ifstream outfile;
            outfile.open("./testMyString.data");
            MyString tmp;
            outfile >> tmp;
            outfile.close();
            // compare read file with solution
            TestOutput<string>(num_tests, num_success, (string)tmp, "test-stream"   , "test 29 - operator <<, operator >>");
        }
        MyString t13("HelloWorld!");
        {
            // save data of t12 to a file
            ofstream infile;
            infile.open("./testMyString.data");
            infile << t13;
            infile.close();
            // read MyString from the file
            ifstream outfile;
            outfile.open("./testMyString.data");
            MyString tmp;
            outfile >> tmp;
            outfile.close();
            // compare read file with solution
            TestOutput<string>(num_tests, num_success, (string)tmp, "HelloWorld!", "test 30 - operator <<, operator >>");
        }
    }
    catch(const char* message)
    {
        cout << "Exception: " << message << endl << endl;
    }
    catch(...)
    {
        cout << "Exception" << endl;
    }

    // print test results
    int total_tests = 30;
    if(num_success == total_tests)
    {
        cout << endl;
        cout << "Congratulation!" << endl;
        cout << "Your program passed all " << num_success << " test cases." << endl;
    }
    else
    {
        cout << endl;
        cout << "Your program failed " << (total_tests - num_success) << " cases out of " << total_tests << " cases." << endl;
    }
    cout << endl;

    return 0;
}

1 个答案:

答案 0 :(得分:1)

MyString::MyString(const char* src)
{
    length = strlen(src);   //set length (c-string)
    string = new char[length];  //allocate memory for string
    strcpy(string, src);    //set string via copy
}

在构造函数上,终止NULL的位置缺少空间。

这是调用复制ctor时螺旋的开始:

MyString& MyString::operator+=(const char* rhs)
{   
    MyString temp(*this);   //create temporary MyString object from 'this'
    ...
}

所以也许在复制ctor中是这样的:

string = new char[length+1];

但是在operator+=中,您需要为旧字符串和新字符串腾出空间。所以您真的要分配:

string = new char[length+strlen(rhs)+1];

然后使用strcpystrcat连接两个字符串。也许像这样:

MyString& MyString::operator+=(const char* rhs)
{   
    size_t new_length = length+strlen(rhs)+1;
    char* new_string = new char[new_length];
    strcpy(new_string, string);
    strcat(new_string, rhs);

    std::swap(new_string, string);
    std::swap(new_length, length);

    delete[] new_string;

    return *this;
}

您可能还有更多问题,但是那一个跳了出去。


  

所讨论的作业先前已经编译并在Linux上使用g ++运行,没有任何问题(并且我认为它应该是正确的,因为我获得了100%的作业)。

我相信Linux也有问题。您只是没有崩溃。

尝试在Linux上使用Valgrind或Address Sanitizer。他们应该为代码提供发现。