Указатель на [-1] th индекс массива

Как делает указатель точки к [-1], th индекс массива производит легальный вывод каждый раз. Что на самом деле происходит в присвоении указателя?

#include<stdio.h>
int main()
{
        int realarray[10];
        int *array = &realarray[-1];

        printf("%p\n", (void *)array);
        return 0;
}

Код произвел:

manav@workstation:~/knr$ gcc -Wall -pedantic ptr.c
manav@workstation:~/knr$ ./a.out
0xbf841140

Править: Если этот сценарий действителен, то могу я использовать это для определения массива, индекс которого запускают от 1 вместо 0, а именно: массив [1], выстройте [2]...

12
задан manav m-n 2 March 2010 в 09:16
поделиться

12 ответов

Вы просто получаете указатель, который содержит адрес этого "воображаемого" места, т.е. местоположение первого элемента &realarray[0] минус размер одного элемента.

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

13
ответ дан 2 December 2019 в 04:16
поделиться

В C и C ++ индексы массива не проверяются во время выполнения. Вы выполняете арифметику указателя, которая может дать или не дать определенные результаты (не здесь).

Однако в C ++ вы можете использовать класс массива, который обеспечивает проверку границ, например boost :: array или std :: tr1 :: array (для добавления к стандартному библиотека в C ++ 0x):

#include <cstdio>
#include <boost/array.hpp>

int main()
{
    try {
        boost::array<int, 10> realarray;
        int* p =  &realarray.at(-1);
        printf("%p\n", (void *)p);
    } catch (const std::exception& e) {
        puts(e.what());
    }
}

Вывод:

array <>: index out of range

Также выдает предупреждение компилятора:

8 test.cpp [Warning] передает отрицательный результат value -0x000000001 'для преобразования 1 из T & boost :: array :: at (size_t) [с T = int, unsigned int N = 10u]'

2
ответ дан 2 December 2019 в 04:16
поделиться

Здесь вы просто выполняете указатель арифметика, он получит первый индексный адрес relarray

Видите, если вы & relarray [+1], вы получите второй адрес элемента массива. поскольку

& relarray [0] указывает на первый индексный адрес.

1
ответ дан 2 December 2019 в 04:16
поделиться

a[b] определяется как *(a+b)

поэтому a[-1] - это *(a-1)

Является ли a-1 действительным указателем и, следовательно, допустимо ли разыменование, зависит от контекста, в котором используется код.

9
ответ дан 2 December 2019 в 04:16
поделиться

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

3
ответ дан 2 December 2019 в 04:16
поделиться

Хотя, как отмечали другие, в данном случае это неопределенное поведение, оно компилируется без предупреждений, потому что в целом , foo [-1] может быть допустимым.

Например, это нормально:

int realarray[10] = { 10, 20, 30, 40 };
int *array = &realarray[2];

printf("%d\n", array[-1]);
3
ответ дан 2 December 2019 в 04:16
поделиться

Он просто указывает на адрес элемента, находящегося в памяти непосредственно перед массивом.

Массив можно рассматривать как указатель. Затем он просто уменьшается на единицу.

1
ответ дан 2 December 2019 в 04:16
поделиться

Вы просто указываете на 4 байта, расположенные перед массивом.

0
ответ дан 2 December 2019 в 04:16
поделиться

Это прекрасно определено. Ваш код гарантированно будет принят всеми компиляторами и никогда не выйдет из строя во время выполнения. Указатели C / C ++ - это числовой тип данных, подчиняющийся правилам арифметики. Работают сложение и вычитание, а обозначение скобок [] - всего лишь причудливый синтаксис для сложения. NULL - это буквально целое число 0.

И вот почему C / C ++ опасны. Компилятор позволит вам без жалоб создавать указатели, указывающие куда угодно. Разыменование дикого указателя в вашем примере * array = 1234; приведет к неопределенному поведению, от незначительного повреждения до сбоя.

Да, вы можете использовать его для индексации с 1. Не делайте этого! Идиома C / C ++ заключается в том, чтобы всегда индексировать с 0. Другие люди, которые видели индексирование кода с 1, были бы склонны «исправить» его, чтобы индексировать с 0.

0
ответ дан 2 December 2019 в 04:16
поделиться

Поведение не определено.

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

3
ответ дан 2 December 2019 в 04:16
поделиться

array указывает на одно место перед начальным адресом realarray . Однако меня смутило, почему это скомпилировано без каких-либо предупреждений.

0
ответ дан 2 December 2019 в 04:16
поделиться

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

printf("%p\n", (void *)array);

, выведите значение элемента массива

printf("%d\n", *array);

Это потому, что печать указателя с %p всегда даст какой-то результат (без каких-либо ошибок), но из него ничего нельзя будет вывести.

0
ответ дан 2 December 2019 в 04:16
поделиться