Как увеличение адреса памяти влияет на указатель - PullRequest
2 голосов
/ 15 июня 2019

Я ищу объяснение того, как увеличение адреса влияет на указатель.

Я узнал о том, как работают указатели C и как делается увеличение указателя, учитывая тип указателя. до сих пор не понимаю следующий случай

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(&a+1);
    printf("%d\n%d\n", *(a+1), *(p-1));
    return 0;
}

я ожидал эту строку

int *p = (int*)(&a+1);

чтобы p указывал на адрес, следующий за массивом "a", поэтому я ожидал вывода:

2 - , поскольку это просто [1]

unknown_number - , поскольку я не знаю, какое значение int отстает на 4 байта (& a + 1)


но фактический результат:

1021 * * 2

5

почему кажется, что p указывает непосредственно на память, сидящую после a?

каков источник моего замешательства?

Ответы [ 3 ]

3 голосов
/ 15 июня 2019

Так что в этом примере &a имеет тип int(*)[5].Когда вы добавляете 1 к нему, он фактически добавляет sizeof(int[5]) - потому что именно так работает арифметика указателей, добавление смещения добавляет размер типа, на который указывает указатель, умноженный на смещение.Таким образом, вы получаете p, чтобы быть последним последним элементом a, после чего вы приводите его к int*, так что теперь у вас есть указатель, указывающий на целое число по адресу, который следует за последним элементом a,Таким образом, вычитая из него 1, вы получаете последний элемент a.

1 голос
/ 15 июня 2019

Два основных понятия:

  • За исключением случаев, когда это операнд оператора sizeof или унарный & или строковый литерал, используемый для инициализации массива символов вобъявление выражение типа "массив N-элементов из T" будет преобразовано ("распад") в выражение типа "указатель на T", а значение выражения будетбыть адресом первого элемента массива.

  • Добавление 1 к выражению типа «указатель на T» дает адрес объекта типа T, непосредственно следующего за текущим объектом.IOW, если p указывает на 4-байтовый int, p+1 указывает на int, следующий сразу за ним.Если p указывает на массив из 5 элементов int, то p+1 указывает на следующий массив из 5 элементов int, следующий сразу за ним.Так работает индексация массива - операция индекса a[i] определяется как *(a + i).Учитывая начальный адрес a (либо выражение указателя, либо выражение массива, которое распадается на указатель), найдите адрес i 'th объекта , следующий за этим адресом, и разыменуйте результат.

Итак, если у вас есть объявление

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

, то верно следующее:

  • выражение a имеет тип "5-элементный массив int" (int [5]) - если выражение не является операндом операторов sizeof или унарных &, оно "затухает", чтобы напечатать указательв int "(int *) и его значением является адрес первого элемента массива (&a[0]).

  • выражение *(a + 1) идентично a[1] и вычисляет второй объект в массиве (2).

  • выражение &a + 1 имеет тип int (*)[5] и возвращает начальный адрес 5-элементного элементамассив int после a.Тип этого выражения преобразуется в int * и присваивается p.

  • выражение p имеет тип int * - вычитая 1 из этого, получаем адрес объекта int, непосредственно предшествующего p, который является последним элементомa.

Графически:

   +–––+
a: | 1 |
   +–––+
   | 2 | <–– a + 1
   +–––+
   | 3 |
   +–––+
   | 4 |
   +–––+
   | 5 | <–– p - 1
   +–––+
   | ? | <–– p (&a + 1)
   +–––+
1 голос
/ 15 июня 2019

Вы можете манипулировать массивом a как указателем на int int *. Но это не то же самое для &a, который является указателем на массив из 5 дюймов: &a + 1 добавит к указателю размер в 5 дюймов.

Просто удалите & перед добавлением 1 к a, и все будет работать так, как вы ожидали:

#include <stdio.h>

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(a+1); // & removed
    printf("%d %d\n", *(a+1), *(p-1));
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...