【问题标题】:Access Violation/Heap Corruption during new char新字符期间访问冲突/堆损坏
【发布时间】:2017-03-21 23:09:27
【问题描述】:

我有一个 C++ 代码示例,我无法解释为什么它会随机导致应用程序因访问冲突或堆损坏而失败。我知道该示例包含当前不受欢迎的代码(直接使用指向 char 的指针),但这仅用于学习目的。如果有人可以查看代码并让我知道您是否看到我遗漏的东西,我将非常感激。谢谢。

class Operand
{
private:
    double value;
    char* message;
public:
    Operand(double value);
    ~Operand();
    char* operator+(const Operand& other);
};

Operand::Operand(double value)
{
    this->value = value;
}

char* Operand::operator+(const Operand& other)
{
    char s[256];
    double sum = this->value + other.value;
    sprintf_s(s, "The sum of %f and %f is %f", this->value, other.value, sum);
    this->message = new char[strlen(s)];  //this is where it sometimes crashes with an access violation
    strcpy_s(this->message, sizeof(s), s);
    return this->message;
}

Operand::~Operand()
{
    if (this->message != nullptr)
        delete[] this->message;
}

int main()
{
    double operand1, operand2;
    cout << "Please input the calculator parameters: operand1 operand2: ";
    cin >> operand1 >> operand2;

    auto Operand1 = Operand(operand1);
    auto Operand2 = Operand(operand2);
    char* message1 = Operand1 + Operand2;
    char* message2 = Operand2 + Operand1;
    cout << message1 << "\n";
    cout << message2 << "\n";

    return 0; //and sometimes it crashes right after outputting to cout
}

我不明白为什么这两个 char* 消息指针会相互干扰,因为它们属于不同的 Operand 实例。如果这确实是它的原因。或者也许我错过了什么。

我真的很感激第二双眼睛,因为我没有想法。谢谢。

【问题讨论】:

    标签: c++


    【解决方案1】:

    有多个错误会导致内存损坏。

    其他答案已经提到内存分配不足。但这是你的问题中最少的。

    未初始化的指针

    Operand 的构造函数无法初始化message 成员。然后,析构函数可能会尝试 delete 一个从未更新过的指针。

    违反 3/5 规则

    显示的类violates the Rule Of The Three。至少,它还需要一个适当的复制构造函数和一个赋值运算符。

    operator+ 内存泄漏

    这将导致内存泄漏,因为如果delete 已经分配了message 的现有内容,则它会失败。

    这些都是在粗略查看代码后立即发现的错误。可能还有几个。

    【讨论】:

    • 感谢您的良好反馈。我意识到我的示例中可能有多个最佳实践被破坏,但这主要是出于学习目的。它的设计并不完美。但我真的很感谢你的指点。
    • 关于未初始化的指针,如果我将它初始化为nullptr,那应该可以解决问题,对吧?因为我已经在删除之前检查了 nullptr
    • 是的,这将解决该特定问题。
    • 关于operator+内存泄露,你确定吗?同样,我意识到这可能是一个非常非正统的代码示例(再次,为了学习目的),但我确实尝试在析构函数中释放内存。
    • 第二次调用operator+会发生什么?
    【解决方案2】:

    你需要为终止的 null 分配一个额外的字节:

    this->message = new char[strlen(s) + 1]; 
    

    【讨论】:

    • 谢谢,我错过了。似乎我在分配后也遇到了另一个问题。在 strcpy_s 调用中,我指定了不正确的 sizeinbytes。指定 strlen(s)+1 使内存冲突消失
    【解决方案3】:

    operator+ 中,您正在为new char[strlen(s)] 的新字符串创建位置。那是一个字符短;你需要为最后的'\0'留出空间。

    当您将字符串复制到其中时,'\0' 会覆盖内存中的下一个字节,这会导致未定义的行为。

    【讨论】:

    • @M.M ,这就是我所说的...愚蠢的 iPad 不听...谢谢。
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多