Вот код, который кажется работающим, пока вы не нажмете -O3 ...
#include <stdio.h>
int main()
{
int i = 0, j = 1, k = 2;
printf("%d %d %d\n", *(&j-1), *(&j), *(&j+1));
return 0;
}
Без оптимизаций получаю «2 1 0»; с оптимизацией я получаю "40 1 2293680". Зачем? Потому что я и К оптимизированы!
Но я взял адрес j и вышел из области памяти, выделенной для j. Это не разрешено стандартом. Скорее всего, ваша проблема вызвана аналогичным отклонением от стандарта.
Я считаю, valgrind часто помогает в такие моменты.
РЕДАКТИРОВАТЬ: Некоторые комментаторы считают, что стандарт допускает произвольную арифметику указателей. Нет. Помните, что в некоторых архитектурах есть забавные схемы адресации, выравнивание может быть важным, и у вас могут возникнуть проблемы, если вы переполните определенные регистры!
Слова стандарта [черновика] о добавлении / вычитании целого числа из / из указателя (выделение добавлено):
"Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, оценка не вызовет переполнения; в противном случае поведение не определено."
Видя, что & j даже не указывает на объект массива, & j-1 и & j + 1 вряд ли могут указывать на часть одного и того же объекта массива. Таким образом, простая оценка & j + 1 (не говоря уже о разыменовании) - это неопределенное поведение.
На x86 мы можем быть достаточно уверены, что добавление единицы к указателю довольно безопасно и просто переносит нас в следующую область памяти. В приведенном выше коде проблема возникает, когда мы делаем предположения о том, что содержит эта память, что, конечно, стандарт не подходит.