我正在使用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;
}
答案 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];
然后使用strcpy
和strcat
连接两个字符串。也许像这样:
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。他们应该为代码提供发现。