Понимание указателей и неправильное распределение памяти?

0

Отказ от ответственности: я очень очень новичок в C++. Я взял один класс два года назад, и сейчас я занимаюсь другим классом, поэтому пытаться вернуться к мышлению очень сложно. Сказав это, я знаю, что мой код очень плох; Я хотел бы помочь и конструктивно критиковать, поэтому, пожалуйста, избегайте откровенного избиения, потому что я знаю, что не знаю, что я делаю.

Цель: я пишу программу, которая принимает два набора пользовательских ввода формы {1 2 3} (любого размера) и выполняет некоторые операции над ними. Но у меня проблемы, просто читая их. Вот быстрый фрагмент файла заголовка, который показывает, какие функции я буду спрашивать:

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 поставляется с элементами int * []). Нам нужно перегрузить оператор ">>", чтобы преобразовать пользовательский ввод в набор. Пользователь вводит два набора. Мы предполагаем, что пользователь достаточно умен, чтобы ввести его в точную форму {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() - это просто функция, которая возвращает значение "размер". Целью вышеприведенного фрагмента является создание пустого Set, затем для каждого int, который находится между "{" и "}", мы изменяем размер массива на 1, а затем помещаем этот int в следующий элемент массива. Кроме того, потоки по-прежнему столь же абстрактны для меня, как и указатели, поэтому почему это кажется немного грубой силой.

У меня проблема с изменением размера. Я хочу - очевидно - для изменения размера, чтобы изменить размер, но это не позволяет этого. То, что я пытаюсь выполнить, - это изменить размер, чтобы изменить указатель на указатель Set *, чтобы указать на новый массив с числом элементов 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];

строка пытается назначить что-то, что еще не существует, поскольку "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 = 0, то как мы можем сделать его больше?

Надеюсь, я включил достаточно, чтобы немного помочь в этом. Я ценю все, что поможет мне понять указатели и как их использовать. Спасибо огромное!

Теги:
pointers
memory-management
exc-bad-access
dynamic-arrays

1 ответ

0
Лучший ответ

Я не уверен, что взял все, но просматриваю код:

  1. Объявление int *elements[]; является незаконным в C++, хотя некоторые компиляторы разрешают его как расширение. Вы должны указать размер массива. Если я скомпилирую gcc, это говорит мне:

    предупреждение: ISO C++ запрещает элементы массива нулевого размера [-Wpedantic]

    int * elements [];

2. Строка if (size!=new_size) истинна всегда, если size не равен new_size. Скорее всего, вы хотите изменить размер массива только тогда, когда new_size больше size.

3. i<new_size || i<size i<new_size || i<size должен, вероятно, быть только i<size.

4. В newelements[i] = *elements[i]; , *elements[i] эквивалентны *(elements[i]) а не (*elements)[i], вы уверены, что это то, что вы хотите?

5.

*elements = newelements;
delete newelements;

Первая строка делает первый элемент (указатель) elements указывать на вновь выделенную память. Вторая строка затем удаляет эту память, поэтому теперь первый элемент elements теперь указывает на освобожденную память. Это не то, что вы хотите. Помните, когда вы назначаете указатель на указатель, он заставляет оба указателя указывать на одну и ту же память. Вам нужно будет удалить старую память, а затем назначить указатель на вновь выделенную память.

6. Также помните, что delete [] отличается от delete. При удалении блока памяти вам нужно будет использовать delete [].

И, надеюсь, это все для учебных целей. В реальном коде C++ вместо этого вы будете использовать std::vector.

  • 0
    Привет Джесси, спасибо за вашу помощь! 1. Ах! Я забыл, что int * elements [] было абсолютно незаконно. Я хотел иметь что-то вроде * elements [size], но я знаю, что размер должен быть объявлен во время компиляции, поэтому я удалил его для дальнейшей работы (и забыл об этом). 2./3. Размер является частью назначения: «Если размер соответствует new_size, то ничего не делать». Кроме того, имеет смысл изменять его размер только тогда, когда new_size> size, но назначение говорит: «resize должен обновлять размер только в том случае, если new_size строго меньше, чем size». Это еще одно разочарование, которое не имеет смысла для меня.
  • 0
    @ErikaH: Кстати, есть много вопросов, которые уже показывают вам, как изменить размер массива, если вы выполните поиск. Вы уверены, что вам даже нужен массив указателей? Похоже, вы просто хотите динамический массив, и у класса Set есть еще больше проблем, ищите «правило трех C ++», чтобы узнать больше. Кроме того, resize should only update size if new_size is strictly smaller than size не имеет смысла (если вы не хотите уменьшить массив), что, вероятно, является опечаткой.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню