Я изучал typedefs и наткнулся на эту программу

РЕДАКТИРОВАТЬ . Почти все ответы касались предупреждений, которые он генерирует. Итак, я пошел дальше и удалил все предупреждения, но вопрос остался прежним.

#include<stdio.h>
typedef int int3[3];
int main(){
    int a[2][3] = {{1,2,3}, {4,5}};
    int3 *p = a;
    int *ip = (int *) a;
    printf("sizeof:\np: %lu\n(*p+0): %lu\n**p: %lu\nip: %lu\n*ip: %lu\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
    printf("---\n");
    printf("p: %p\tp+1: %p\n*p: %p\t*p+1: %p\n**p: %d\nip: %p\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
    return 0;
}

За один прогон показывает:

sizeof:
p: 8
(*p+0): 8
**p: 4
ip: 8
*ip: 4
---
p: 0x7ffe36df31b0   p+1: 0x7ffe36df31bc
*p: 0x7ffe36df31b0  *p+1: 0x7ffe36df31b4
**p: 1
ip: 0x7ffe36df31b0
*ip: 1

Мой вопрос: Если p и * p равны
и ** р = 1
тогда почему не * p = 1?

Предусмотренный размер указателя = 8 и размер целого = 4
Даже если принять во внимание арифметику указателя, * p должно быть не менее 0xkk kk kk kk 00 00 00 01
k - любое шестнадцатеричное число (рассмотрим младший порядок)
потому что разыменование того же адреса, что и Int должно дать 1

< Сильный > ИЗМЕНИТЬ : Чтобы прояснить ситуацию, рассмотрим следующую таблицу:

+-----------+----------------------+------------------+
|Variable   | Value                | Address          |
|           |                      |                  |
|           |                      |                  |
| p         | 0x7ffe36df31b0       |                  |
|           |                      |                  |
|*p         | 0x7ffe36df31b0       |  0x7ffe36df31b0  |
|           |                      |                  |
|**p        | 1                    |  0x7ffe36df31b0  |
+-----------+----------------------+------------------+

Как * p и ** p могут иметь один и тот же адрес, но различное значение?

0
Hritik 2 Май 2019 в 02:35

2 ответа

Лучший ответ

Во-первых, обратите внимание, что этот код в запутанной путанице нарушений ограничений в сочетании с затуханием массива для генерировать вывод сомнительной полезности. Но я постараюсь ответить на ваш вопрос о том, что происходит, и попробую использовать мирские объяснения, не прибегая к цитатам из Стандарта Си, поскольку другие уже ответили таким образом.

Как * p и ** p могут иметь один и тот же адрес, но различное значение?

Потому что p это указатель на массив.

Данный

typedef int int3[3];
int3 *p;

Это означает, что *p является трехмерным массивом. Обратите внимание, что

int3 *p = a;

Это нарушение ограничения, как отмечено в другом месте. Вы можете заставить «работать» с приведением, но это все еще в корне неверно, и код только «сходит с рук», потому что адрес массива является адресом первого элемента этого массива. - и ваша текущая реализация не достаточно дифференцирует типы указателей, поскольку они в корне несовместимы. Выберите реализацию, в которой простой int * является, скажем, 32-битным значением смещения, в то время как массив будет иметь в качестве адреса как 32-битный сегмент , так и 32-битное значение смещения, и код, скорее всего, сгенерирует чепуху, если не прекратится. Вот почему стандарт C требует, чтобы указатели были «совместимыми типами» - потому что указатели вовсе не должны быть совместимыми.

Помимо этой проблемы, инициализация / присваивание вашей реализации может рассматриваться как

int3 *p = ( int3 * ) a;

Поскольку это «работает», это означает, что p содержит адрес трехэлементного массива значений int. Таким образом, разыменование p с помощью *p аналогично a[0] или первому трехэлементному массиву int в двумерном массиве a.

Так что же такое *p?

В этом случае он точно такой же, как a[0], массив. И такая пустая ссылка на массив распадается на адрес *, и этот адрес тот же < strong> type как указатель на элемент массива. И значением этого адреса будет значение адреса первого элемента массива.

Таким образом, *p, представляющий собой массив из трех элементов int, может сам разыменовываться и вычисляться для первого элемента a[0] или a[0][0]. Итак, **p такой же, как a[0][0].

И a[0][0] - или **p - это int, который инициализируется значением 1.

Хотя *p это a[0] и адрес этого первого элемента.

* - Многие люди говорят, что массив «распадается на указатель» или «массив является указателем», но мне нравится «распадается на адрес», потому что указатель может быть назначен, но адрес просто равен - он не может быть назначен самому себе, так же как сам массив не может быть назначен, но адрес может быть назначен чему-то другому, например, указателю. Обратите внимание, что когда массив передается функции, адрес массива фактически передается как фактический указатель. Указатель является параметром функции, и этот параметр функции может быть назначен ...

2
Andrew Henle 6 Май 2019 в 14:33

Опубликованный код, когда скомпилирован с:

gcc -c -Wall -Wextra -Wconversion -pedantic -std=gnu11 

Приводит к следующим сообщениям компилятора:

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.

Компилятор заканчивает, говоря, что компиляция прошла успешно. Это НЕ означает, что можно нормально запускать этот код и ожидать правильных результатов / вывода.

Когда вы исправляете код так, чтобы он был аккуратно скомпилирован, то, пожалуйста, опубликуйте РЕДАКТИРОВАТЬ свой вопрос, который содержит измененный / исправленный код.

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.
1
user3629249 2 Май 2019 в 22:32