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

#include <iostream>
using namespace std;

int* flipArray(int input[], int n)
{
    int output[n];
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
    {
        output[pos++] = input[i];
    }
    int* p = output;
    for (int k = 0; k < n; k++)
        cout << *p-k << endl << endl;
    return p;
}

int main()
{
    const int SIZE = 5;
    int firstArray[SIZE];
    for (int n = 0; n < SIZE; n++)
    {
        firstArray[n] = n+1;
    }
    int* a;
    a = flipArray(firstArray, SIZE);
    for (int j = 0; j < SIZE; j++)
        cout << *a-j << endl;

    cout << endl;
    cout << *a << 't' << *a+1 << 't' << *a+2;
    return 0;
}

я пытаюсь перевернуть firstArray с помощью функции, которая возвращает указатель, но я изо всех сил пытаюсь понять, как работает доступ к индексу с помощью указателя.

вот почему я в замешательстве: В пределах функции flipArray, следующий for-loop:

for (int k = 0; k < n; k++)
    cout << *p-k << ' ';

печать "5 4 3 2 1" в консоли. Это было мое понимание того, что я должен получить доступ к элементу вектора с *(p+k), а не *(p-k). Если я напечатаю *(p+k), "5 6 7 8 9" печатается на приставка. Если я печатаю массив без указателей и использую k в качестве местоположения индекса," 5 4 3 2 1 " печатается на консоль.

в моей основной функции, однако, значения *a, которому назначен указатель p из функции flipArray, я не получаю те же результаты:

for (int j = 0; j < SIZE; j++)
    cout << *a-j << endl;

печать 5 Ноль -1 -2 -3 к консоли, и

    for (int j = 0; j < SIZE; j++)
    cout << *a+j << endl;

печать 5 Два Три Четыре 5 на консоль.

далее, я думал, что указатель местоположения *p и указатель местоположения *a надо же! Но когда я печатаю адрес &p в функции я получаю местоположение 0x28fde0, и когда я печатаю адрес &a в основном, я получаю местоположение 0x28fedc. Конечно, это было сделано во время того же пробега.

может ли кто-нибудь сказать мне, где я сбился с пути? Спасибо!


спасибо всем за информативные ответы.

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

int* flipArray(int input[], int n)
{
    int* output = new int[n];
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
        output[pos++] = input[i];
    return output;
}

int main()
{
    const int SIZE = 5;
    int firstArray[SIZE];
    for (int n = 0; n < SIZE; n++)
    {
        firstArray[n] = n+1;
    }
    int* a;
    a = flipArray(firstArray, SIZE);
    for (int j = 0; j < SIZE; j++)
        cout << a[j] << " "; // can also be written as *(a+j), which is more prone to bugs
    delete [] a;
    return 0;
}

будет ли вывод указателя удален при возврате функции flipArray? Если нет, как я должен удалить вывод, а также вернуть его? Удаление указателя a в моей основной функции то же самое, что удаление вывода, потому что они указывают на одно и то же место?

3 ответов


было указано, что ваша главная проблема исходит из приоритет операторов. The * оператор *p - k оценивается до -. Это означает, что k будет вычитаться из значения int, на которое указывает p.

это огромная боль, поэтому скобки pointer[k] обычно используются. Бывают ситуации, когда с помощью указателя арифметика *(pointer + k) больше смысла, но это может быть источником ошибок.

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


у вас есть вторая проблема:

объявление output на стеке в качестве локальной переменной, то вы возвращаете output. Когда вы вернетесь к предыдущему кадру стека, этот указатель будет указывать на освобожденный буфер:
int* flipArray(int input[], int n)
{
    int output[n]; // allocated on the stack
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
    {
        output[pos++] = input[i];
    }
    int* p = output;
    for (int k = 0; k < n; k++)
        cout << *p-k << endl << endl;
    return p; // this stack frame ends.
}

это означает, что содержимое буфера может быть перезаписывается, если пространство, используемое буфером, перераспределено. Использовать new выделить в куче:

int* output = new int[n];

обязательно позвоните delete на указателе, когда вы закончите его использовать.

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


обновление:

вопрос: когда эта функция возвращает массив все еще существует в память, и ее местоположение хранится в указателе a. Возвращает ли вывод значения удалить его? Если нет, будет ли удаление указателя a, когда я закончу с ним в основной функции, служить той же цели?

когда вы delete указатель, память, указанная на этот указатель, освобождается, и указатель остается висящим. Ссылка на удаленный указатель указывает на технически свободную память, что плохо. Если библиотека распределителя решит, что она хочет повторно использовать это пространство, ваш буфер, который теперь находится в свободном пространстве, будет перераспределено. Это означает, что ваш буфер потеряет всю целостность данных, и данные внутри него не могут быть доверены.

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

int* p = new int[10];
...
delete p;
p = NULL;
...
p[0] = 0; // this will now crash because you are accessing NULL.

for (int k = 0; k < n; k++)
    cout << *p-k ;

насколько я понимаю, я должен иметь доступ к элементу вектора с *(p+k), а не *(p-k).

ваше понимание правильно.Вы не получаете доступ к массиву здесь.p указывает на первый элемент 5 и каждый раз, когда k вычитается из него, что дает вам 5-0 5-1 5-2 и так далее, что эквивалентно массива filpped.Так что если вы хотите получить доступ к массиву через указатель

for (int k = 0; k < n; k++)
    cout << *(p+k) ;// Note the paranthesis

for (int k = 0; k < n; k++)
    cout << *p-k << endl << endl;

что этот код делает совсем не то, что вы думаете.

*p - k будет обрабатываться как

*p = 5 - 0 = 5
*p = 5 - 1 = 4

и так далее не *(p+k) или *(p-k)

для вашего понимания :

int a[5] = { 1,2,6,4,5};

для доступа к 3-му элементу в массиве вы делаете

a[2] = *(a+2)

, а не

*a + 2

*(a + 2) = 6 и *a + 2 = 1 + 2 = 3

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