Ответ 1
Да, это UB.
Из [basic.compound]:
Каждое значение типа указателя является одним из следующих:
- указатель на объект или функцию (указывается, что указатель указывает на объект или функцию) или
- указатель за концом объекта ([expr.add]) или
- значение нулевого указателя ([conv.ptr]) для этого типа или
- неверное значение указателя.
Значение типа указателя, которое является указателем на конец объекта или мимо него, представляет адрес первого байта в памяти ([intro.memory]), занятый объектом или первым байтом в памяти после окончания занимаемого объектом, соответственно. [Примечание. Указатель за конец объекта ([expr.add]) не считается указывающим на несвязанный объект типа объекта, который может быть расположен по этому адресу. Значение указателя становится недействительным, когда хранящееся хранилище заканчивается его длительностью хранения; см. [basic.stc]. - конечная нота]
И [expr.add]/4:
Когда выражение, которое имеет интегральный тип, добавляется или вычитается из указателя, результат имеет тип операнда указателя. Если выражение P указывает на элемент x [i] объекта массива x с n элементами, 86 выражения P + J и J + P (где J имеет значение j) указывают на (возможно, гипотетический) элемент x [i + j], если 0≤i + j≤n; в противном случае поведение undefined. Аналогично, выражение P - J указывает на (возможно, гипотетический) элемент x [i-j], если 0≤i-j≤n; в противном случае поведение undefined.
Итак, &a[0][0] + 10
- это "указатель мимо конца объекта", это минус конечный указатель первого массива. Вы не можете добавить еще один указатель - для этого случая нет определенного поведения.
Указатель не может быть как указателем "за конец", так и "указателем на объект" (интерпретация &a[0][0] + 10
, как если бы он был &a[1][0]
). Это одно или другое.