Что возвращает «(новый тип [n]) + 1»?

0

Ссылаясь на http://www.cplusplus.com/doc/tutorial/dynamic/, говорится, что new оператор возвращает указатель на начало выделенного нового выделенного блока памяти. Предположим еще раз, что любой указатель имеет функцию арифметики указателя, которая может сделать так, что p + 1 указывает на следующую позицию в памяти, если p является указателем. Исходя из вышеприведенных предположений, я попытался сделать следующий блок,

#include <iostream>
using namespace std;
int main(){
    int * ptr = (new int [4]) + 1;
    ptr[3] = 2;
    cout << ptr[3] << endl;
    /*Before delete the dynamic allocated memory, 
      it should be necessary to let ptr point to the 
      beginning of it, add one line to do that:
      --ptr;*/
    delete [] ptr;
}

Я ожидал, что ptr[3] должен выходить за пределы диапазона выделенной памяти. Однако результат все же дает 2. Почему арифметика указателя становится бесполезной? Или это действительно new Type возвращает объект *Type?

Спасибо за любую помощь.

  • 6
    Доступ к элементам за пределами массива - неопределенное поведение. Программа не может аварийно завершить работу сразу или вообще. Ущерб все еще сделано, хотя.
  • 0
    Он возвращает указатель на второй элемент выделенного массива и вызывает утечку памяти.
Показать ещё 14 комментариев
Теги:
pointers
pointer-arithmetic

4 ответа

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

Я ожидал, что ptr[3] должен выходить за пределы диапазона выделенной памяти.

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

Однако результат все же дает 2.

Это означает, что доступная память была недоступна за пределами массива, поэтому не удалось обнаружить недопустимый доступ. Вместо этого он перезаписал память, которая не принадлежала массиву - возможно, она не использовалась, или, возможно, вы перезаписали некоторые другие данные, что позже приведет к ошибочным ошибкам.

Почему арифметика указателя становится бесполезной?

Это полезно как любая арифметика указателя. Арифметика указателя не может обнаружить конец массива, поэтому вы получаете неопределенное поведение, если оно выйдет за пределы диапазона.

Или это действительно new Type возвращает объект *Type?

new Type[] возвращает указатель Type* на выделенный массив. Это ведет себя так же, как и любой другой указатель, поэтому добавление одного дает вам указатель на второй элемент.

delete [] ptr также дает неопределенное поведение, поскольку ptr больше не указывает на начало выделенного массива.

  • 0
    Спасибо. Ваш ответ потрясающий.
2

Выход за пределы границы - неопределенное поведение.

Вы можете получить разные результаты при компиляции с помощью компилятора differet, разных флагов компиляции, даже работающих в разное время. Компьютер может сдуться, и ваш монитор может гореть.

Возврат правильного значения является одним из неопределенных поведений тоже.

1
int * ptr = new int [4];

будет указывать на ptr[0], поэтому

int * ptr = (new int [4]) + 1;

будет pont для ptr[1] и вы не сможете освободить ptr если вы не сделаете что-то вроде delete (ptr--);

  • 0
    Я не понимаю, кто будет указывать на ptr [1]? это сам птр?
  • 0
    Спасибо, @SaniHuttunen, ты прав. Во всяком случае, это не очень хорошая практика.
Показать ещё 5 комментариев
1

C/C++ позволяет назначать/считывать значения в/из вне границ памяти, так как это неопределенное поведение.

Например, это действительный код:

int *array = new int[10];
array[10] = 5;
std::cout<<array[10];

Однако при этом вы можете повредить другие структуры данных, если они имеют память, расположенную рядом с вашим массивом.

  • 0
    Нет, это не так. Это позволяет вам использовать значение указателя за концом, но разыменование это неопределенное поведение. Повторяйте ваши изменения, либо это разрешено, либо это неопределенное поведение. Вы не можете иметь это в обоих направлениях. -1
  • 0
    @EJP Я только сказал, что вам разрешено «назначать», а теперь отредактировал также и «прочитанную» часть. Я ничего не говорил о разыменовании.
Показать ещё 1 комментарий

Ещё вопросы

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