C++ _块类型在“返回0”之后有效(pHead->nBlockUse)
我正在编写一个程序,我必须编写自己的字符串类和药剂类。我知道此运行时错误通常是在程序删除未分配的内容时引起的,但它发生在main中的“return 0”之后。我已经对它进行了逐行调试,并尝试了一些方法来消除运行时错误,但没有任何效果。有人能帮我解决这个问题吗 这是我的密码:C++ _块类型在“返回0”之后有效(pHead->nBlockUse),c++,debugging,C++,Debugging,我正在编写一个程序,我必须编写自己的字符串类和药剂类。我知道此运行时错误通常是在程序删除未分配的内容时引起的,但它发生在main中的“return 0”之后。我已经对它进行了逐行调试,并尝试了一些方法来消除运行时错误,但没有任何效果。有人能帮我解决这个问题吗 这是我的密码: //Main #include "Potion.h" #include <iostream> using std::cout; using std::endl; void TotalCost( Potion A
//Main
#include "Potion.h"
#include <iostream>
using std::cout;
using std::endl;
void TotalCost( Potion ArrayofPotions[5] )
{
String Currency[4] = {"Platinum", "Gold", "Silver" ,"Copper"};
int TotalCost[4] = {0, 0, 0, 0};
int Cost[4] = {0, 0, 0, 0};
for (short i = 0; i < 5; i++)
{
for (short k = 0; k < 4; k++)
{
Cost[k] = ArrayofPotions[i].ConvertCost(k);
TotalCost[k] += Cost[k];
if ( i != 0 )
TotalCost[k] = ArrayofPotions[k].CalculateCost(TotalCost[k - 1], TotalCost[k]);
}
}
cout << "\nTotal cost for all potions: ";
for (short i = 0; i < 4; i++)
{
cout << TotalCost[i] << ' ';
Currency[i].Display();
}
}
int main()
{
Potion Haggling("Potion of Haggling", "You haggle for 10% better prices for 30 seconds",
"Weak", "0.80.0.4.");
Potion Strength("Draught of Strength", "You can carry 20% more for 300 seconds",
"Low", "2.60.5.1.");
Potion Health("Solution of Health", "You are 30% tougher for 60 seconds",
"Mild", "2.20.5.1.");
Potion Stealth("Philter of Stealth", "You are 40% harder to detect for 60 seconds",
"Moderate", "0.90.5.1.");
Potion Waterbreathing("Elixir of Waterbreathing", "You can breathe underwater for 60 seconds",
"Strong", "2.10.5.0.");
Potion ArrayOfPotions[5] = {Haggling, Strength, Health, Stealth, Waterbreathing};
for (short i = 0; i < 5; i++)
ArrayOfPotions[i].DisplayPotions();
TotalCost(ArrayOfPotions);
system("pause");
return 0;
}
//String class
class String
{
public:
String() : m_str(nullptr)
{ }
String(char chr) : m_str(nullptr)
{
m_str = new char;
*m_str = ch;
}
String(char * str)
{
if (str != nullptr)
{
m_str = new char[strlen(str) + 1];
strcpy(m_str, str);
}
}
String(const String & copy) : m_str(copy.m_str)
{ }
String& operator=(const String & rhs)
{
if ( this != &rhs )
{
delete [] m_str;
m_str = new char[strlen(rhs.m_str) + 1];
strcpy(m_str, rhs.m_str);
}
return *this;
}
~String()
{
delete [] m_str;
}
void Display() const
{
cout << m_str;
}
char * GetStr() const
{
return m_str;
}
String Upper()
{
char * check = this->m_str;
for (unsigned short i = 0; i < strlen( this->m_str ); i++, check++)
{
if ( *check > 96 && *check < 123 )
{
*check -= 32;
}
else
m_str = this->m_str;
}
return m_str;
}
private:
char * m_str;
};
//Potion class
#include "String.h"
class Potion
{
public:
Potion() : m_name(nullptr), m_description(nullptr), m_potency(nullptr),
m_cost(nullptr)
{ }
Potion(String name, String description, String potency, String cost)
{
m_name = name;
m_description = description;
m_potency = potency.Upper();
m_cost = cost;
}
Potion(const Potion & copy) : m_name(copy.m_name), m_description(copy.m_description),
m_potency(copy.m_potency), m_cost(copy.m_cost)
{ }
int ConvertCost(int index)
{
int cost = 0;
char * new_cost = m_cost.GetStr();
char * temp_string = new char[strlen( new_cost ) + 1];
strcpy(temp_string, new_cost);
char * temp = strtok( temp_string, "." );
for (short k = 0; k != index; k++)
temp = strtok( NULL, "." );
cost = atoi( temp );
delete [] temp_string;
return cost;
}
int CalculateCost(int & cost1, int cost2)
{
if (cost > 99)
{
cost1++;
cost2 -= 100;
}
return cost2;
}
void DisplayPotions()
{
String Currency[4] = {"Platinum", "Gold", "Silver" ,"Copper"};
int cost = 0;
m_name.Display();
m_description.Display();
m_potency.Display();
for (short i = 0; i < 4; i++)
{
cost = ConvertCost(i);
if (cost != 0)
{
cout << ConvertCost(i) << ' ';
Currency[i].Display();
}
}
}
private:
String m_name;
String m_description;
String m_potency;
String m_cost;
};
很抱歉,它太长了,我遗漏了一些输出格式,但我确实需要一些帮助
另外,我的教授希望我们将成本从字符串转换为int,并且必须以0.0.0.0格式输入。这就是为什么它是这样写的。您的赋值运算符被破坏了,因为它从右侧复制指针。 您需要遵循与复制构造函数中相同的过程
String(const String & copy) : m_str(new char[strlen(copy.m_str)+1])
{
strcpy(m_str, copy.m_str);
}
顺便说一下,复制构造函数也被破坏了,因为如果rhs为空,它将失败
在表示空字符串时使用空字符串是一种更安全的方法,即使用而不是空ptr。
它避免了大量的空检查
此构造函数也已损坏:
String(char * str)
{
if (str != nullptr)
{
m_str = new char[strlen(str) + 1];
strcpy(m_str, str);
}
}
String(char chr) : m_str(nullptr)
{
m_str = new char;
*m_str = ch;
}
因为如果传递null ptr,m_str将处于未初始化状态,并且经常这样做
此构造函数也已损坏:
String(char * str)
{
if (str != nullptr)
{
m_str = new char[strlen(str) + 1];
strcpy(m_str, str);
}
}
String(char chr) : m_str(nullptr)
{
m_str = new char;
*m_str = ch;
}
因为它不构造以零结尾的字符串
你需要
m_str = new char[2];
m_str[0] = ch;
m_str[1] = 0;
赋值运算符已断开,因为它从右侧复制指针。 您需要遵循与复制构造函数中相同的过程
String(const String & copy) : m_str(new char[strlen(copy.m_str)+1])
{
strcpy(m_str, copy.m_str);
}
顺便说一下,复制构造函数也被破坏了,因为如果rhs为空,它将失败
在表示空字符串时使用空字符串是一种更安全的方法,即使用而不是空ptr。
它避免了大量的空检查
此构造函数也已损坏:
String(char * str)
{
if (str != nullptr)
{
m_str = new char[strlen(str) + 1];
strcpy(m_str, str);
}
}
String(char chr) : m_str(nullptr)
{
m_str = new char;
*m_str = ch;
}
因为如果传递null ptr,m_str将处于未初始化状态,并且经常这样做
此构造函数也已损坏:
String(char * str)
{
if (str != nullptr)
{
m_str = new char[strlen(str) + 1];
strcpy(m_str, str);
}
}
String(char chr) : m_str(nullptr)
{
m_str = new char;
*m_str = ch;
}
因为它不构造以零结尾的字符串
你需要
m_str = new char[2];
m_str[0] = ch;
m_str[1] = 0;
正如其他人所说,您的构造函数已损坏。除此之外,赋值运算符还以一种微妙的方式被破坏 解决此问题的最简单方法是将大部分赋值运算符代码移动到复制构造函数
String(const String & copy) : m_str(new char[strlen(copy.m_str)+1])
{
strcpy(m_str, copy.m_str);
}
至于赋值运算符,缺陷在于它在调用new[]之前删除内存。如果new[]抛出异常,会发生什么?您已销毁旧数据,无法恢复数据
与如何编写赋值运算符不同,更好的方法是:
#include <algorithm>
//...
String& operator=(String rhs)
{
std::swap(rhs.m_str, m_str);
return *this;
}
这很简单,而且有效。它需要一个有效的复制构造函数和字符串的有效析构函数。由于您提供了这两个函数,因此编写赋值运算符变得很简单
请参见复制/交换习惯用法:
这也确保了如果new[]抛出异常,原始字符串不会被破坏。std::swap只交换这两个项——如果不能使用std::swap,那么就编写自己的函数来交换指针,因为这应该很容易实现。正如其他人所说,您的构造函数是坏的。除此之外,赋值运算符还以一种微妙的方式被破坏 解决此问题的最简单方法是将大部分赋值运算符代码移动到复制构造函数
String(const String & copy) : m_str(new char[strlen(copy.m_str)+1])
{
strcpy(m_str, copy.m_str);
}
至于赋值运算符,缺陷在于它在调用new[]之前删除内存。如果new[]抛出异常,会发生什么?您已销毁旧数据,无法恢复数据
与如何编写赋值运算符不同,更好的方法是:
#include <algorithm>
//...
String& operator=(String rhs)
{
std::swap(rhs.m_str, m_str);
return *this;
}
这很简单,而且有效。它需要一个有效的复制构造函数和字符串的有效析构函数。由于您提供了这两个函数,因此编写赋值运算符变得很简单
请参见复制/交换习惯用法:
这也确保了如果new[]抛出异常,原始字符串不会被破坏。std::swap只交换这两个项-如果不能使用std::swap,那么就编写自己的函数来交换指针,因为这应该很容易实现。String&operator=const String©:m_strcopy.m_str这太糟糕了,两个实例都有相同的指针。您需要执行与复制构造函数中相同的操作,并且不要忘记删除旧指针。不要使用像96和132这样的数字,使用像“a”和“z”这样的字符。它可以帮助那些与您不同,没有记住ASCII表的人。您可以省略else分支,而不是在m_str=this->m_str;中什么都不做;。调试项目并在发生断言冲突时查看执行堆栈。查找堆栈中作为代码一部分的第一项。它应该是字符串的析构函数,调用delete[]。这是给你的线索。正在删除内存,而之前该内存已被删除。复制构造函数/op=是一个错误。我把它们倒过来了,但我把它修好了。@colematthew4如果复制构造函数和驴
点火操作是反向的,为什么要测试这个!=&rhs?复制构造函数永远不需要对此进行测试。String&operator=const String©:m_strcopy.m_str这太糟糕了,两个实例都有相同的指针。您需要执行与复制构造函数中相同的操作,并且不要忘记删除旧指针。不要使用像96和132这样的数字,使用像“a”和“z”这样的字符。它可以帮助那些与您不同,没有记住ASCII表的人。您可以省略else分支,而不是在m_str=this->m_str;中什么都不做;。调试项目并在发生断言冲突时查看执行堆栈。查找堆栈中作为代码一部分的第一项。它应该是字符串的析构函数,调用delete[]。这是给你的线索。正在删除内存,而之前该内存已被删除。复制构造函数/op=是一个错误。我把它们倒过来了,但我把它修好了。@colematthew4如果复制构造函数和赋值op倒过来了,为什么要测试它!=&rhs?复制构造函数永远不需要为此进行测试。