【问题标题】:can't figure out where the heap overwriting is无法弄清楚堆覆盖在哪里
【发布时间】:2021-06-27 10:49:54
【问题描述】:
#include<iostream>

using namespace std;

class Text{
public:
~Text(){
    delete data;
}
    char* data{};
    int mSize{};
    void fill(char* stringInput) {
        mSize = strlen(stringInput);
        data = new char [mSize];
        for (int i = 0; i < mSize; i++){
            data[i] = stringInput[i];
        }
    }

};

class myString{
public:
    explicit myString(int size){ // constructor
        strAmount = size;
        strings = new Text [size];
    }

    ~myString(){ // destructor
        delete[] strings;
    }
    void addString(char* input){
        strings[filledAmount].fill(input);
        filledAmount++;
    }
    void delString(int pos){
        for ( int i = pos; i < filledAmount; i++){
            swap(strings[i], strings[i+1]);
        }
        strings[filledAmount].data = nullptr;
        strings[filledAmount].mSize = 0;
        filledAmount--;
    }
    void eraseEverything(){
        for ( int i = 0; i < filledAmount; i++){
            strings[i].data = {};
            strings[i].mSize = 0;
        }
        filledAmount = 0;
    }
    int maxString() const {
        int index{};
        for ( int i = 0 ; i < filledAmount; i++){
            if (strings[i].mSize > strings[index].mSize){
                index = i;
            }
        }
        return index;
    }
    int charAmount(){
        int counter{};
        for(int i = 0 ; i < filledAmount; i++){
            counter+=strings[i].mSize;
        }
        return counter;
    }
    double digitPercentage(){
        int digitsAmount{};
        for(int i = 0; i < filledAmount; i++){
            for ( int j = 0; j < strings[i].mSize; j++){
                if (isdigit(strings[i].data[j])){
                    digitsAmount++;
                }
            }
        }
        double digitPercent = (digitsAmount/(double)charAmount())*100;
        return digitPercent;
    }

    int filledAmount{};

    int strAmount{};
    Text* strings;

};

void render_text(myString& obj) {
    for (int k = 0; k < obj.filledAmount; k++) {
        for (int i = 0; i < obj.strings[k].mSize; i++)
            cout << obj.strings[k].data[i];
        cout << endl;
    }
    cout << endl;
    }

int main(){
    myString a(5);

    a.addString((char *) "zxc 1v1 forever shadow fiend");
    a.addString((char *) "This is a string");
    a.addString((char *) "12345");
    a.addString((char *) "Hello");
    a.addString((char *) "A1oha Dance");
    render_text(a);

    a.delString(1);
    render_text(a);

    int maxInd = a.maxString();
    cout << "Max string :\n";
    for (int i = 0; i < a.strings[maxInd].mSize; i++) {
        cout << a.strings[maxInd].data[i];
    }
    cout << "\n\n";
    }

请帮我找到崩溃点。我想它在析构函数极点崩溃了,但我还是想不通。

这个有点像自己写的字符串类,问题是我找不到问题开始的地方。

我还认为析构函数试图从堆中删除太多内存,因此编译器会阻止它这样做。我可以以某种方式更改strings 数组的大小吗?

【问题讨论】:

  • fill 中,您应该在字符串末尾放置一个 NUL 终止符。这将“浪费”一个字节,但它会使调试和互操作性变得更加容易。

标签: c++ class destructor heap-memory


【解决方案1】:

在地址sanitizers的帮助下,我已经修复了你所有的内存错误

这里的主要变化是:

  • 添加复制构造函数和复制赋值运算符
  • 手动删除函数delString中的最后一个元素

虽然代码现在可以工作,但它并不是真正的现代 c++ 样式代码。我强烈建议您使用 std::string 替换您的 Text 类。使用std::vector 替换动态数组。然后你就会远离记忆错误的痛苦。 delString应该换成vector::erase,比你的手写算法简洁多了。

https://en.cppreference.com/w/cpp/string/basic_string https://en.cppreference.com/w/cpp/container/vector

我强烈建议使用std::stringstd::vector 重写代码

#include <cstring>
#include <iostream>

using namespace std;

class Text {
 public:
  ~Text() { delete[] data; }
  char* data{};
  int mSize{};
  Text() = default;
  Text(const Text& oth) {
    mSize = oth.mSize;
    data = new char[mSize];
    std::copy(oth.data, oth.data + oth.mSize, data);
  }
  Text& operator=(const Text& oth) {
    delete[] data;
    mSize = oth.mSize;
    data = new char[mSize];
    std::copy(oth.data, oth.data + oth.mSize, data);
    return *this;
  }

  void fill(char* stringInput) {
    mSize = strlen(stringInput) + 1;
    data = new char[mSize];
    for (int i = 0; i < mSize; i++) {
      data[i] = stringInput[i];
    }
  }
};

class myString {
 public:
  explicit myString(int size) {  // constructor
    strAmount = size;
    strings = new Text[size];
  }

  myString(const myString& oth) {
    strAmount = oth.strAmount;
    strings = new Text[oth.strAmount];
    for (size_t i = 0; i < strAmount; ++i) {
      strings[i] = oth.strings[i];
    }
  }
  myString& operator=(const myString& oth) {
    delete[] strings;

    strAmount = oth.strAmount;
    strings = new Text[oth.strAmount];
    for (size_t i = 0; i < strAmount; ++i) {
      strings[i] = oth.strings[i];
    }
    return *this;
  }

  ~myString() {  // destructor
    delete[] strings;
  }
  void addString(char* input) {
    strings[filledAmount].fill(input);
    filledAmount++;
  }
  void delString(int pos) {
    for (int i = pos; i < filledAmount; i++) {
      swap(strings[i], strings[i + 1]);
    }
    delete[] strings[filledAmount].data;
    strings[filledAmount].data = nullptr;
    strings[filledAmount].mSize = 0;
    filledAmount--;
  }
  void eraseEverything() {
    for (int i = 0; i < filledAmount; i++) {
      strings[i].data = {};
      strings[i].mSize = 0;
    }
    filledAmount = 0;
  }
  int maxString() const {
    int index{};
    for (int i = 0; i < filledAmount; i++) {
      if (strings[i].mSize > strings[index].mSize) {
        index = i;
      }
    }
    return index;
  }
  int charAmount() {
    int counter{};
    for (int i = 0; i < filledAmount; i++) {
      counter += strings[i].mSize;
    }
    return counter;
  }
  double digitPercentage() {
    int digitsAmount{};
    for (int i = 0; i < filledAmount; i++) {
      for (int j = 0; j < strings[i].mSize; j++) {
        if (isdigit(strings[i].data[j])) {
          digitsAmount++;
        }
      }
    }
    double digitPercent = (digitsAmount / (double)charAmount()) * 100;
    return digitPercent;
  }

  int filledAmount{};

  int strAmount{};
  Text* strings = nullptr;
};

void render_text(myString& obj) {
  for (int k = 0; k < obj.filledAmount; k++) {
    for (int i = 0; i < obj.strings[k].mSize; i++)
      cout << obj.strings[k].data[i];
    cout << endl;
  }
  cout << endl;
}

int main() {
  myString a(6);

  a.addString((char*)"zxc 1v1 forever shadow fiend");
  a.addString((char*)"This is a string");
  a.addString((char*)"12345");
  a.addString((char*)"Hello");
  a.addString((char*)"A1oha Dance");
  render_text(a);

  a.delString(1);
  render_text(a);

  int maxInd = a.maxString();
  cout << "Max string :\n";
  for (int i = 0; i < a.strings[maxInd].mSize; i++) {
    cout << a.strings[maxInd].data[i];
  }
  cout << "\n\n";
  return 0;
}

【讨论】:

  • a.addString((char*)"zxc 1v1 forever shadow fiend"); -- 这很危险。您应该将函数原型更改为const char *。第二件事是您的用户定义的赋值运算符在调用new[] 之前发出delete[] 调用——如果new[] 抛出异常并且对象已损坏。
  • @PaulMcKenzie 谢谢!这些确实很危险,我这里主要修复了内存泄漏和双重释放问题,请随时编辑我的答案以使其更准确。
猜你喜欢
  • 2019-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多