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

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

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

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

Выход кода:

[email protected]:~/knr$ gcc -Wall -pedantic ptr.c
[email protected]:~/knr$ ./a.out
0xbf841140

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

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

Поведение undefined.

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

Ответ 4

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

Ответ 5

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

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

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

printf("%d\n", array[-1]);

Ответ 6

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

Однако на С++ вы можете использовать класс массива, который выполняет проверки границ, например boost::array или std::tr1::array (для добавления в стандартную библиотеку в С++ 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());
    }
}

Вывод:

массив < > : индекс за пределами диапазона

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

8 test.cpp [Предупреждение] минус отрицательный значение -0x000000001' for converting 1 of T & увеличить:: массив:: в (size_t) [с T = int, unsigned int N = 10u] '

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

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

Ответ 12

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

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

напечатать значение элемента массива

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

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