【问题标题】:Understanding pointers and bad memory allocation?了解指针和错误的内存分配?
【发布时间】:2014-02-02 20:09:13
【问题描述】:

免责声明:我对 C++ 非常非常陌生。两年前我上了一门课,现在我正在上另一门课,所以试图恢复这种心态是很困难的。话虽如此,我知道我的代码非常糟糕。我需要帮助和建设性的批评,所以请避免直接抨击,因为我知道我真的不知道自己在做什么。

目标:我正在编写一个程序,它接收两个 {1 2 3}(任意大小)形式的用户输入集,并对它们执行一些操作。但是我无法简单地读入它们。这是头文件的快速 sn-p,它显示了我将要询问的功能:

class Set{

  public:

    Set();                  //Constructor for empty set.
    Set(int element);       //Constructor for set of one element
    ~Set();

    unsigned int getSize() const;                          
    int operator[](const int e) const;  

    friend ostream& operator<<(ostream& oss, const Set& output);   
    friend istream& operator>>(istream& ss, Set& target);         

  private:

    int size;
    int *elements[];        
    void resize(unsigned int new_size);
};

还有更多,但我只是向您展示所有必要的东西。

对于赋值,我们创建了一个名为 Set 的类,但该集合必须存储为一个数组。每个 Set 都有一个指针数组(即 Set 类带有 int *elements[])。我们需要重载“>>”运算符以将用户输入转换为 Set。用户输入两个集。我们假设用户足够聪明,可以以精确的形式 {1 2 3 4} 输入它,但它可以是任何大小。这是我的重载>>。

istream& operator>>(istream& ss, Set& target){ 

  //The constructor Set target; creates an empty Set with array size=0.

  char c;      

  if (ss.peek()=='}') ss >> c; 
  if (ss.peek()==EOF) ss >> c;

  ss >> c;     //First we read in the '{' character.
  int num;

  while (ss.peek()!='}'){
    ss >> num;
    target.resize(target.getSize()+1); 
    *target.elements[target.getSize()-1]=num;
  };
  return ss;
};

getSize() 只是一个返回值“size”的函数。上述 sn-p 的目标是创建一个空 Set,然后对于“{”和“}”之间的每个 int,我们将数组大小调整 1,然后将该 int 放入数组的下一个元素中。此外,流对我来说仍然像指针一样抽象,所以这就是为什么这看起来有点暴力。

问题我遇到的是调整大小。我想要 - 显然 - 调整大小以更改大小,但它不允许这样做。我想要完成的是调整大小以更改被调用的 Set 的 *elements 指针以指向具有 new_size 个元素的新数组。然后我想释放该指针以避免内存泄漏。

void Set::resize(unsigned int new_size){

  if (size!=new_size){
      int *newelements = new int[new_size];

      for (int i=0; i<new_size || i<size; i++){
          newelements[i] = *elements[i]; 
      };

      *elements = newelements;
      delete newelements;

      if (size>new_size) size=new_size;
   };

};

我知道有一点是错误的:当我在 ">>" 的定义中调用 newset.resize 时,

newelements[i] = *elements[i];

line 正在尝试分配尚不存在的内容,因为“num”尚未分配给 *newset.elements[i]。但是,如果我尝试在“>>”中切换这些顺序,使其变成这样......

*target.elements[target.getSize()]=num;
target.resize(target.getSize()+1); 

...这应该没有意义,因为目标数组的大小是0,所以我不能说target[0]=num;

我知道的另一件事是错误的:我使用指针的方式一定有问题,因为如果我尝试在调整大小定义中说 size=new_size ,我收到“EXC_BAD_ACCESS”错误。实际上,如果我按原样运行,我会收到相同的错误消息。

此外,在作业中,我们被告知“仅当 new_size 严格小于 size 时,才应调整大小。”我不明白这怎么可能奏效。如果我们必须从一个 size=0 的初始化数组开始,那么我们怎样才能让它更大呢?

我希望我已经包含了足够多的内容,以便在这方面获得一些帮助。我很感激任何能帮助我理解指针以及如何使用它们的东西。非常感谢!

【问题讨论】:

    标签: c++ pointers memory-management exc-bad-access dynamic-arrays


    【解决方案1】:

    我不确定我是否捡到了所有东西,但扫描代码:

    1. 声明 int *elements[]; 在 C++ 中是非法的,尽管一些编译器允许它作为扩展。 您必须指定数组大小。 如果我用 gcc 编译,它会告诉我:

      警告:ISO C++ 禁止零大小数组“元素”[-Wpedantic]

      int *elements[];

    2. 行if (size!=new_size) 始终为真,除非size 不等于new_size。 只有当new_size 大于 大于size 时,您很可能想要调整数组的大小。

    3. i&lt;new_size || i&lt;size 应该只是i&lt;size

    4. 在newelements[i] = *elements[i]; 中,*elements[i] 等价于*(elements[i])不是 (*elements)[i],你确定这是你想要的吗?

    5.

    *elements = newelements;
    delete newelements;
    

    第一行使elements 的第一个元素(指针)指向新分配的内存。然后第二行删除该内存,所以现在elements 的第一个元素现在指向已释放的内存。那不是你想要的。 请记住,当您将指针分配给指针时,它会使两个指针指向同一内存。您需要做的是删除 old 内存,然后分配指针指向新分配的内存。

    6. 还要记住delete []delete 不同。删除内存块时需要使用delete []

    希望这一切都是为了学习目的。在真正的 C++ 代码中,您将使用 std::vector

    【讨论】:

    • 嗨,杰西,感谢您的帮助! 1.啊!我忘记了 int *elements[] 是绝对非法的。我的意思是有类似 *elements[size] 的东西,但我知道必须在编译时声明 size,所以这就是为什么我删除它以便稍后处理(并忘记它)。 2./3.尺寸是任务的一部分:“如果尺寸与 new_size 匹配,则什么也不做。”此外,仅当 new_size>size 时才调整它的大小是有意义的,但是分配说“如果 new_size 严格小于 size,则调整大小应该只更新大小。”这是另一种对我来说没有直观意义的挫败感。
    • @ErikaH:顺便说一句,are plenty of questions 已经向您展示了如何在进行搜索时调整数组大小。你确定你甚至需要一个指针数组吗?看起来你只是想要一个动态数组,而你 Set 类有更多问题,搜索“三个 C++ 规则”以了解更多信息。 resize should only update size if new_size is strictly smaller than size 也没有意义(除非你想缩小数组),这可能是一个错字。
    • 另外,刚刚注意到if (ss.peek()==EOF) ss &gt;&gt; c; 是不必要的。如果您到达EOF,那么您将无法从流中读取更多内容。
    • 这个作业确实要求一个指针数组,而且是关于学习“三巨头”。
    • @ErikaH:在这种情况下,您需要定义适当的析构函数、复制构造函数和赋值运算符。此外,如果您使用的是 C++11,则还需要添加移动操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-04
    • 2020-11-21
    • 2019-03-31
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多