С
Это напомнило мне об ошибке, с которой я столкнулся, когда узнал C. К сожалению, оригинальный вариант, похоже, не работает с текущим GCC, но этот по-прежнему работает:
#define ARR_SIZE 1234
int main() {
int i = ARR_SIZE;
int arr[ARR_SIZE];
while(i >= 0) {
(--i)[arr] = 0;
}
i = *(int*)0;
}
Это очевидно segfaults, потому что мы разыменовываем нулевой указатель, правильно?
Неверно - на самом деле, это бесконечный цикл, поскольку наше условие цикла отключено на единицу. Из-за префикса декремента, iработает с 1023 до -1. Это означает, что присвоение перезаписывает не только все элементы arr, но также и область памяти непосредственно перед ним - что, как оказалось, является местом, где iхранится. Достигнув -1, iпереписывает себя 0и , таким образом , условие цикла выполняется снова ...
Это был оригинальный вариант I, который я больше не могу воспроизвести:
То же самое сработало с iподъемом вверх от 0 и отключением на единицу. Последний GCC всегда хранится iраньше arrв памяти; это должно было отличаться в старых версиях (возможно, в зависимости от порядка объявления). Это была настоящая ошибка, которую я произвел в одной из моих первых игрушечных программ, работающих с массивами.
Кроме того, это очевидно, если вы знаете, как работают указатели в C, но может удивить, если вы этого не сделаете:
Вы можете подумать, что присваивание для (--i)[arr]бросает ошибку, но это допустимо и эквивалентно arr[--i]. Выражение a[x]является просто синтаксическим сахаром, для *(a + x)которого вычисляется и разыменовывается указатель на индексированный элемент; дополнение, конечно, коммутативно и, следовательно, эквивалентно *(x + a).