В чем разница между следующими декларациями:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
Каково общее правило для понимания более сложных объявлений?
c
arrays
pointers
variable-declaration
Джордж
источник
источник
const
иvolatile
классификаторы, которые являются важным и сложным, не хватает в этой статье.Ответы:
Третий такой же, как первый.
Общее правило - приоритет оператора . Это может стать еще более сложным, поскольку указатели функций входят в картину.
источник
( ) [ ]
связываются слева направо и имеют более высокий приоритет, чем*
считанныеint* arr[8]
как массив размера 8, где каждый элемент указывает на int, иint (*arr)[8]
как указатель на массив размера 8, который содержит целые числаИспользуйте программу cdecl , как предложено K & R.
Это работает и в другую сторону.
источник
Я не знаю, есть ли у него официальное название, но я называю это Right-Left Thingy (TM).
Начните с переменной, затем идите направо, налево и направо ... и так далее.
arr1
это массив из 8 указателей на целые числа.arr2
является указателем (скобка справа-слева) на массив из 8 целых чисел.arr3
это массив из 8 указателей на целые числа.Это должно помочь вам со сложными декларациями.
источник
int *a[][10]
то время как второе преуспевает.( ) [ ]
слева направо и справа налево* &
источник
[5]
) представляет внутреннее измерение. Это означает, что(*a[8])
это первое измерение и, следовательно, внешнее представление массива. То, на чтоa
указывает каждый элемент в пределах, - это другой целочисленный массив размером 5.Ответ на последние два также можно вычесть из золотого правила в C:
int (*arr2)[8];
Что произойдет, если вы разыграете
arr2
? Вы получаете массив из 8 целых чисел.int *(arr3[8]);
Что произойдет, если вы берете элемент из
arr3
? Вы получаете указатель на целое число.Это также помогает при работе с указателями на функции. Возьмите пример с сигьюса:
float *(*x)(void )
Что происходит при разыменовании
x
? Вы получаете функцию, которую можете вызывать без аргументов. Что происходит, когда вы звоните? Он вернет указатель наfloat
.Однако приоритет оператора всегда сложен. Однако использование круглых скобок также может сбивать с толку, потому что объявление следует за использованием. По крайней мере, для меня, интуитивно
arr2
выглядит как массив из 8 указателей на целые, но на самом деле все наоборот. Просто нужно привыкнуть. Достаточно причины, чтобы всегда добавлять комментарий к этим объявлениям, если вы спросите меня :)редактировать: пример
Кстати, я просто наткнулся на следующую ситуацию: функция, которая имеет статическую матрицу и использует арифметику указателей, чтобы увидеть, находится ли указатель строки вне границ. Пример:
Вывод:
Обратите внимание, что значение border никогда не меняется, поэтому компилятор может оптимизировать его. Это отличается от того, что вы могли бы изначально использовать::,
const int (*border)[3]
который объявляет границу как указатель на массив из 3 целых чисел, который не изменит значение, пока существует переменная. Тем не менее, этот указатель может указывать на любой другой такой массив в любое время. Вместо этого мы хотим такое поведение для аргумента (потому что эта функция не меняет ни одно из этих целых чисел). Декларация следует за использованием.(ps: не стесняйтесь улучшать этот образец!)
источник
источник
Как правило, правые унарные операторы (например
[]
,()
и т. Д.) Имеют преимущество перед левыми. Таким образом,int *(*ptr)()[];
будет указатель, который указывает на функцию, которая возвращает массив указателей на int (получите правильные операторы, как только сможете, как только выйдете из скобок)источник
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
под GCC 8 с$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
позволяет использовать выражение, подобноеp()[3]
(или(*p)()[3]
), позже.int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
и назовите это так:foo(arr)[4];
что должно содержатьarr[2][4]
, верно?Я думаю, что мы можем использовать простое правило ..
«
ptr
это указатель на« идти вправо .. его »)« теперь идите влево его a »(« выйди иди вправо »()« так »для функции, которая не принимает аргументов« уходи влево »и возвращает указатель« ходи вправо "к массиву" иди влево "целых чисел"источник
)
, теперь иди налево ... это*
«указатель на» иди вправо ... это)
, теперь иди налево ... это a(
выходите, идите направо()
так "к функции, которая не принимает аргументов" идите направо ...[]
"и возвращает массив указателей " идите направо;
, так идите налево ...*
"на" идти налево ...int
"целые числа"Вот интересный сайт, который объясняет, как читать сложные типы в C: http://www.unixwiz.net/techtips/reading-cdecl.html
источник
Вот как я это интерпретирую:
Итак, здесь мы применим
[]
предыдущее*
, делая утверждение эквивалентным:Это может быть прочитано как, (значение (значение в i-м индексе чего-то)) является целым числом. Итак, (значение в i-м индексе чего-либо) является (целочисленным указателем), что делает массив массивом целочисленных указателей.
Во втором
Чтобы разобраться в этом утверждении, вы должны быть знакомы с этим фактом:
Итак, заменив
somethingElse
на(*something)
, мы получаем*(*something + i)
, что является целым числом согласно объявлению. Итак,(*something)
нам дан массив, который делает что-то эквивалентное (указатель на массив) .источник
Я думаю, что второе заявление многих сбивает с толку. Вот простой способ понять это.
Позволяет иметь массив целых чисел, то есть
int B[8]
.Давайте также иметь переменную A , который указывает на B. Теперь, значение в точке А есть В, то есть
(*A) == B
. Следовательно, A указывает на массив целых чисел. В вашем вопросе arr похож на A.Аналогично, в
int* (*C) [8]
C указатель на массив указателей на целое число.источник
В этом объявлении
arr1
представлен массив из 5 указателей на целые числа. Причина: квадратные скобки имеют более высокий приоритет над * (оператор разыменования). И в этом типе число строк фиксировано (5 здесь), но количество столбцов является переменным.В этом объявлении
arr2
указатель на целочисленный массив из 5 элементов. Причина: здесь скобки () имеют более высокий приоритет, чем []. И в этом типе число строк является переменным, но количество столбцов является фиксированным (5 здесь).источник
В указателе на целое число, если указатель увеличивается, то идет следующее целое число.
в массиве указателей, если указатель увеличивается, он переходит к следующему массиву
источник