странный выходной вопрос в с - PullRequest
0 голосов
/ 26 июня 2018
1)  #include <stdio.h>
    int main()
  {
       int a[5] = {1,2,3,4,5};
       int *ptr = (int*)(&a+1);
        printf("%d %d", *(a+1), *(ptr-1));
        return 0;
   }

на выходе 2 5 . &a означает адрес a[0], поэтому &a+1 должен быть адресом a[1]. Таким образом, ptr должен содержать адрес a[1]. *(a+1) будет 2, но *(ptr-1) также должно быть 2. Я не могу понять, как это печатать 5.

Ответы [ 4 ]

0 голосов
/ 26 июня 2018

Во-первых, вы сказали: &a означает адрес a[0], поэтому &a+1 должен быть адресом [1]? Нет, вы не правы. &a означает адрес a, а не a[0]. И &a+1 означает, что он увеличивается на размер всего массива , а не только на один размер элементов, а a+1 означает адрес a[1].

Здесь

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

допустим, что базовый адрес a равен 0x100

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116 ..  
   LSB
    |
    a  

Когда вы делаете

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

Где ptr баллов? первый (&a+1) выполнен, и он получил приращений на весь размер массива т.е.

(&a+1) == (0x100 + 1*20) /* &a+1 here it increments by array size */
       == 0x120

Так что теперь ptr указывает на

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116  0x120  
    a                                     |
                                         ptr points here

Теперь, когда вы печатаете как

printf("%d %d", *(a+1), *(ptr-1));

Здесь

*(a+1) == *(0x100 + 1*4) /* multiplied by 4 bcz of elements is of int type*/
       == *(0x104) /* value at 0x104 location */
       == 2 (it prints 2)

И

*(ptr-1)  == *(0x120 - 1*4)
          == *(0x116) /* prints value at 0x116 memory location */
          == 5

Примечание: - Здесь

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

тип &a имеет int(*)[5], то есть указатель на массив из 5 элементов, но вы преобразуете его в тип int*, как указано @someprogrammerdude, оно нарушает строгое псевдоним и приводит к неопределенному поведению.

Правильно это

int *ptr = a+1;
0 голосов
/ 26 июня 2018

&a - это не адрес a[0], а адрес a. Значения могут быть одинаковыми, но типы различны. Это важно, когда дело доходит до арифметики указателей.

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

Когда вы затем оцениваете *(ptr - 1), оператор - вычитает 1 * sizeof(int) из байтового значения ptr, так что теперь он указывает на последний элемент массива, то есть 5, и это то, что распечатаны.

0 голосов
/ 26 июня 2018

Это выражение - важная вещь: &a+1. На самом деле это (&a)+1, что равно (&a)[1], что будет указателем на один элемент после конца массива.

Если мы посмотрим на это более «графически», то это будет выглядеть так, с добавлением соответствующих указателей:

+------+------+------+------+------+
| a[0] | a[1] | a[2] | a[3] | a[4] |
+------+------+------+------+------+
^      ^                           ^
|      |                           |
|      &a[1] (equal to *(a + 1))   |
|                                  |
&a[0] (equal to a)                 |
|                                  |
&a                                 &a+1

Прежде всего, тип &a равен int (*)[5], поэтому ваш приведение к int * нарушит строгое алиасинг (что приводит к неопределенному поведению ).

Во-вторых, поскольку ptr фактически указывает на то, что будет a[5], тогда ptr - 1 будет указывать на a[4].

0 голосов
/ 26 июня 2018

&a дает адрес массива в виде указателя массива , int (*)[5]. Это тип указателя, который указывает на массив в целом, поэтому, если вы сделаете с ним арифметику указателя, +1 будет означать +sizeof(int[5]), что не соответствует вашим ожиданиям.

Правильный код:

int *ptr = a+1;

Примечательно, что актер (int*) скрывал эту ошибку. Не используйте приведения, чтобы заглушить ошибки компилятора, которые вы не понимаете!

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