При изучении C (или C++, или и того, и другого), что, давайте будем правдой, все меньше и меньше людей делают в наши дни, требуется некоторое время, чтобы понять указатели или даже просто изучить синтаксис указателей, разыменование, многомерные массивы и, конечно же, — указатели на функции. Некоторым из них требуется время, чтобы привыкнуть и распознать, что происходит при чтении чужого кода. Давайте освежим в памяти некоторые основы работы с массивами, прежде чем я объясню один странный прием, который на первый взгляд удивителен, но в то же время вполне логичен.

Итак, массив можно объявить по-разному, например int a[10]; — это массив из десяти целых чисел. Синтаксис массива приятен и прост для понимания и чтения, но когда вы начинаете делать что-то реальное, включающее более сложные типы или многомерные массивы, становится проще просто рассматривать ваши массивы как блоки памяти с указателем на первый элемент. Нет другого способа создать массив неизвестного во время компиляции, кроме объявления указателя и выделения памяти вручную.

Если вы объявите указатель: int *pa;, то вы можете присвоить ему адрес первого элемента в a следующим образом: pa = &a[0];. Теперь, используя арифметику указателей, легко получить доступ ко всем остальным элементам вашего массива: например, *(pa+1) указывает на второй элемент, а присваивание y = *(pa+1) присваивает значение второго элемента int переменной y. Конечно, *(pa+i) дает вам доступ к любому элементу и совпадает с a[i] (только будьте осторожны, чтобы не выйти за пределы выделенной памяти).

И вот, наконец, неожиданный трюк. C всегда преобразует синтаксис вашего массива a[i] в *(a+i), и при этом ему не важно, какая из a и i является переменной массива, а какая — индексом. Таким образом, i[a] работает так же, как a[i], и работает с пронумерованными индексами, поэтому a[3] совпадает с 3[a] и дает вам четвертый элемент массива.

Эту небольшую статью я хочу посвятить покойному Деннису Ритчи, смерть которого в далеком 2011 году прошла практически незамеченной.