Переворачивание массива с помощью указателей
#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
заботиться не возвращая указатель на локальную переменная, которая приведет к неопределенному поведению