Используется ли арифметика указателей вне массивов?

Я думаю, что я правильно понимаю семантику арифметики указателя, но я когда-либо видел примеры при работе с массивами. Есть ли у него какие-либо другие виды использования, которые не могут быть достигнуты с помощью менее непрозрачных средств? Я уверен, что вы могли бы найти способ с умным кастингом, чтобы использовать его для доступа к членам структуры, но я не уверен, почему вы беспокоитесь. Меня больше всего интересует C, но я буду отмечать с помощью С++, потому что ответ, вероятно, применим и там.

Изменить, на основе полученных ответов: Я знаю, что указатели могут использоваться во многих контекстах без массива. Я специально интересуюсь арифметикой на указателях, например. увеличивая, принимая разницу и т.д.

Ответы

Ответ 1

Если вы следуете стандарту языка в письме, то арифметика указателя определяется только при указании на массив, а не в любом другом случае.

Указатель может указывать на любой элемент массива или на один шаг за конец массива.

Ответ 2

Арифметика указателя по определению в C происходит только на массивах. Однако, поскольку каждый объект имеет представление, состоящее из наложенного массива unsigned char [sizeof object], он также действителен для выполнения арифметики указателя на этом представлении. Например:

struct foo {
    int a, b, c;
} bar;

/* Equivalent to: bar.c = 1; */
*(int *)((unsigned char *)&bar + offsetof(struct foo, c)) = 1;

Фактически char * будет работать так же хорошо.

Ответ 3

Из верхней части моей главы я знаю, что он использовался в XOR-связанных списках (очень изящный), и я видел, как он использовался в очень хакерские рекурсии.

С другой стороны, очень трудно найти использование, поскольку в соответствии со стандартным указателем арифмический определяется только в пределах массива.

Ответ 4

a[n] является "просто" синтаксическим сахаром для *(a + n). Для lulz попробуйте следующее

int a[2];
0[a] = 10;
1[a] = 20;

Таким образом, можно утверждать, что индексирование и арифметика указателей являются просто взаимозаменяемым синтаксисом.

Ответ 5

Арифметика указателя определяется только для массивов. Добавление целого числа к указателю, который не указывает на элемент массива, вызывает поведение undefined.

Ответ 6

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

Например, стек (удерживающие переменные и адреса) управляется путем добавления или вычитания значений из указателя стека. (В этом случае стек можно назвать стеком на основе массива.)

Ответ 7

Здесь случай для арифметики указателя вне (строго определенных) массивов:

double d = 0.5;
unsigned char *bytes = (void *)&d;
for(size_t i = 0; i < sizeof d; i++)
    printf("Byte %zu of d is %hhu\n", i, bytes[i]);

Зачем вам это делать? Я не знаю. Но если вы хотите посмотреть побитовое представление объекта (полезно для таких вещей, как memcpy и memcmp), вам нужно будет указать свои адреса на unsigned char * (или signed char *s, если хотите), и работать с ними побайтно. (Если ваша задача не слишком сложна, вы даже можете написать код для работы по слову, который будет реализован в большинстве реализаций memcpy. Однако тот же принцип просто заменит char на int32_t.)

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