Создание массивов в куче и обращение к ним с помощью указателей

У меня возникли проблемы с пониманием следующего фрагмента кода, который, как я надеялся, создаст массив в куче и заполнит его символами от 9 до 0 (я знаю, что могу просто индексировать массив как обычный массив стека с нотацией [] сделать это, но я делаю это таким образом, чтобы попытаться понять указатели более глубоко):

int *ptrHeapArray = new int[10]; 

    for(int f=9; f>=0 ;f--)
    {
        *ptrHeapArray = f;
        ptrHeapArray++;
    }
    for(int f=0; f<10; f++)
        cout << ptrHeapArray[f]  << "\n";

Он выводит совершенно неожиданные значения.

Как я понял из вышеизложенного, команда "new" создает массив в куче и отправляет мне обратно указатель на адрес, где находится массив. Поскольку указатель, который я назначаю (ptrHeapArray), имеет размер int, я предположил, что могу использовать приращение указателя для навигации по массиву. Однако результаты показывают, что мои предположения неверны.

Это навело меня на мысль, что, возможно, указатель, переданный ключевым словом «новое», является просто указателем на весь массив и по какой-то причине не может использоваться для прохода по массиву. Поэтому я попытался создать еще один указатель на указатель, возвращаемый ключевым словом «новое», и использовал его для заполнения моего массива:

int *ptrHeapArray = new int[10];  //array to hold FRANK data in 32 bit chunks
int *ptrToHeapArrayPointer = ptrHeapArray;

for(int f=9; f>=0 ;f--)
{
    *ptrToHeapArrayPointer = f;
    ptrToHeapArrayPointer++;
}
for(int f=0; f<10; f++)
    cout << ptrHeapArray[f]  << "\n";   

Это сработало нормально. Может ли кто-нибудь объяснить мне, почему я должен был это сделать и не мог просто использовать указатель, переданный мне с помощью ключевого слова «новое»?

Спасибо


person Columbo    schedule 22.06.2009    source источник


Ответы (6)


Линия

ptrHeapArray++;

в вашем первом цикле for увеличивается указатель, так что он больше не указывает на начало массива.

Линия

int *ptrHeapArray = new int[10];

выделяет память для 10 целых чисел и указывает ptrHeapArray на начало этой памяти. Затем в цикле for вы перемещаете этот указатель. Когда ptrHeapArray указывает на третье из целых чисел:

[0] [1] [2] [3] [4]
 ^       ^       ^
orig.    |       |
         |       +-- ptrHeapArray[2]
         |
         +-- ptrHeapArray now points here

тогда ptrHeapArray[2] даст вам целое число в позиции, первоначально пронумерованной 4.

person balpha    schedule 22.06.2009
comment
Это в основном забивает голову вашего массива - person Nathan Fellman; 22.06.2009
comment
@ Натан: не говори так. Вы не различаете указатель и то, на что он указывает. Это различие часто бывает трудным для начинающих программистов. Голова массива вообще не затирается (перезаписывается). Это без изменений. На него просто больше нет указателя. - person MSalters; 22.06.2009

Вы изменяете указатель в коде. После первого цикла в первом фрагменте указатель будет указывать на конец массива, а не на начало. Чтобы было понятнее, это тоже сработает (не предлагается, но демонстрирует поведение):

int *ptrHeapArray = new int[10]; 

for(int f=9; f>=0 ;f--)
{
    *ptrHeapArray = f;
    ptrHeapArray++;
}

ptrHeapArray -= 10; // reset the pointer to its original location

for(int f=0; f<10; f++)
    cout << ptrHeapArray[f]  << "\n";
person mmx    schedule 22.06.2009

Ваш ptrToHeapArrayPointer назван неправильно, это просто стандартный int ptr, на который вы указали то же место, что и ptrHeapArray. Если вы переименуете его в currentPositionPtr, ваш код будет иметь для вас больше смысла.

person Patrick    schedule 22.06.2009

Когда вы делаете ptrHeapArray++, он увеличивает ptrHeapArray. Когда вы приходите распечатать данные, ptrHeapArray больше не указывает на начало массива.

person Tom Carter    schedule 22.06.2009

Проблема в том, что в вашем первом примере ptrHeapArray изначально установлен в начало массива. Когда вы повторяете свой цикл, вы увеличиваете указатель, и к концу цикла for вы указываете на последний элемент в массиве. Когда вы проходите цикл for для отображения всех ваших значений, вы индексируете значения после конца массива, поскольку ptrHeapArray указывает на последний элемент в выделенном вами массиве.

Также важно помнить, что вы, вероятно, должны быть уверены, что не потеряете исходный указатель, который вы получили от использования оператора new, чтобы вы могли правильно освободить память, которая была выделена в куче.

person heavyd    schedule 22.06.2009

В первом цикле вы увеличили свой указатель ptrHeapArray до конца массива. Итак, после выполнения первого цикла for ваш указатель указывает на конец массива, а не на начало. Следовательно, когда вы пытаетесь распечатать содержимое массива, вы обращаетесь к недопустимым выделениям памяти, и поведение будет неожиданным. Во втором случае вы берете копию своего начального адреса, прежде чем присваивать значения массиву. Поэтому, когда вы пытаетесь распечатать содержимое с помощью копии, оно будет указывать на начало массива.

person Naveen    schedule 22.06.2009