fork download
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. // arr - массив из 3 int.
  6. int arr[] = { 10, 20, 30 };
  7.  
  8. // arrptr - указатель на массив неопределенного количества int.
  9. int (*arrptr)[] = &arr;
  10.  
  11. // intptr - указатель на первый элемент массива. & не нужен, потому что
  12. // см. парой строк ниже.
  13. int *intptr = arr;
  14.  
  15. // 1. При использовании имени массива, оно всегда неявно кастится
  16. // к указателю на тип его элементов, если это имя не является операндом
  17. // для & или sizeof. Тут arr кастится к int *, но это отнюдь не означает,
  18. // что arr является int *.
  19.  
  20. // Мы делаем каст аргумента в void *, чтобы осчастливить компилятор.
  21. // Это требуется лишь для %p по стандарту, но в обычном мире на
  22. // существующих машинах он совершенно ничего не делает со
  23. // значением указателя).
  24. printf("Address of the first element "
  25. "(using imlicit cast of arr): %p\n", (void *) arr);
  26.  
  27. // 2. Тут все просто? Хуй там. Тут arr кастится к int *, потом [0] делает
  28. // адресную арифметику (address + sizeof(int) * 0), но так как слева &
  29. // то дереференса не происходит.
  30. printf("Address of the first element "
  31. "(using &arr[0]): %p\n", (void *) &arr[0]);
  32.  
  33. // 3. Адрес массива в виде указателя на массив численно равен указателю
  34. // на первый элемент.
  35. printf("Address of arr using & directly (&arr): %p and from arrptr value: %p\n",
  36. (void *) &arr, (void *) arrptr);
  37.  
  38. // Раз адрес массива совпадает с адресом его первого элемента, то
  39. // дереференс указателя на массив не поменяет численное значение
  40. // этого указателя (на нормальных машинах), а поменяет только его
  41. // тип.
  42. printf("Dereferencing pointer to an array = %p changes its type\n"
  43. "\tbut not its value: %p\n", (void *) &arr, (void *) *(&arr));
  44.  
  45. // Читаем через указатель на int, скучно.
  46. printf("Dereferencing intptr (int *): %d\n", *(intptr));
  47.  
  48. // См. (1), плюс дереференс.
  49. printf("Dereferencing arr implicitly casted to (int *): %d\n", *arr);
  50.  
  51. // См. (2), но [] делает дереференс. Т.е, *((int *) (arr)) + 0).
  52. printf("Using [] sugar on arr: %d\n", arr[0]);
  53.  
  54. // Опять первый дереференс указателя на массив меняет его тип с
  55. // "указателя на массив int" на "указатель на int", а второй уже
  56. // явно (*) или неявно ([]) дереференсит и читает значение.
  57. printf("Dereferencing &arr twice: %d\n", *(*(&arr)));
  58. printf("Dereferencing arrptr twice: %d\n", (*arrptr)[0]);
  59.  
  60. // Все вышесказанное справедливо для обычных машин и обычного кода.
  61. // В теории может существовать компилятор, соблюдающий стандарт, у
  62. // которого указатели различных типов не будут равны, у которого явно
  63. // взятый указатель на массив не будет совпадать с указателем на первый
  64. ///элемент. Т.е., хотя так никто не делает (потом что не нужно), но
  65. // компилятор, у которого вот такое поведение, вполне нормален:
  66. // (uintptr_t) (&arr) != (uintptr_t) (&arr[0])
  67. // но при этом неявный каст по стандарту обязан работать везде:
  68. // (uintptr_t) (arr) == (uintptr_t) (&arr[0])
  69. }
  70.  
Success #stdin #stdout 0s 9424KB
stdin
Standard input is empty
stdout
Address of the first element (using imlicit cast of arr): 0x7ffde35d6540
Address of the first element (using &arr[0]): 0x7ffde35d6540
Address of arr using & directly (&arr): 0x7ffde35d6540 and from arrptr value: 0x7ffde35d6540
Dereferencing pointer to an array = 0x7ffde35d6540 changes its type
	but not its value: 0x7ffde35d6540
Dereferencing intptr (int *): 10
Dereferencing arr implicitly casted to (int *): 10
Using [] sugar on arr: 10
Dereferencing &arr twice: 10
Dereferencing arrptr twice: 10