Отладка Xcode C изменяет значения указателей при пошаговом выполнении

Я отлаживаю код C, где у меня есть указатель внутри указателя на структуру с именем board. Есть функция, где я печатаю плату:

static void board_print(board *b){
    int i,j;
    char data;
    for (i = 0; i < size; i++) {
        for (j = 0; j < size; j++) {
            data = b->data[i * size + j];
            if(data){
                printf("X ");
            }else{
                printf("O ");
            }
        }
        printf("\n");
    }
}

Вот странная часть. Когда я сначала нажимаю точку останова в начале первого цикла for, все в порядке, мои данные верны, все указатели работают и т. д., как показано ниже:

первый

Затем я вхожу в цикл в первый раз, когда i и j равны нулю, а b->data[0] должно быть абсолютно допустимым, как это было два шага назад. Внезапно, как только я наступаю на строку data = b->data[i * size + j];, указатель данных превращается в нулевой указатель. Когда я выполняю строку, я (очевидно) получаю ошибку неправильного доступа, как показано ниже:

секунда

Что может быть причиной? Я использовал C раньше, и я довольно хорошо разобрался с ним, но я никогда не видел, чтобы значение указателя внезапно менялось на нулевое, когда я выполнял простую однопоточную программу C. Я использую Apple LLVM Compiler 4.1 для компиляции и lldb для отладки, которые используются по умолчанию в XCode 4.5.

Обновление: такое же поведение наблюдалось при компиляции с помощью gcc и отладке с помощью gdb. Почти стопроцентная ошибка на моей стороне, но я понятия не имею, что не так с кодом.

Обновление №2: я заметил кое-что еще более странное в gcc/gdb. Непосредственно перед выполнением строки data = b->data[i * size + j]; я без проблем могу получить доступ ко всему из отладчика. Сразу после выполнения этой строки я не могу полностью получить доступ к b->data, включая значения, к которым я обращался непосредственно перед шагом:

третий

После строки $4 = ..., которая успешно выполнилась в отладчике, я перешагнул через эту строку. Тогда у меня есть различные ошибки адресации, как показано выше. Я действительно понятия не имею, что происходит...

Обновление №3: я заметил кое-что очень странное. Здесь сначала посмотрите на исправление, которое я реализовал. Этот начал работать без проблем, когда я полностью избавился от переменной с именем data:

четвертый

Теперь внимательно посмотрите на снимок экрана, который я загрузил с обновлением № 2: сразу после того, как я присвоил значение локальной переменной с именем data, адрес b->data также изменился. Это похоже на побочный эффект задания. Но я понятия не имею, в чем причина этого.


person Can Poyrazoğlu    schedule 29.12.2012    source источник
comment
Не думаю, что резко изменится. Можете ли вы попробовать использовать другую переменную для индекса и проверки? например, var = i * size + j; и проверьте, что b->data[var] действительно является допустимым указателем, а var не выходит за пределы допустимого диапазона, и действительно, что вы рассчитали как правильный индекс?   -  person P.P    schedule 29.12.2012
comment
Возникает ли та же ошибка, когда вы не используете отладчик?   -  person DCoder    schedule 29.12.2012
comment
что-то нашел: см. мое последнее обновление (3)   -  person Can Poyrazoğlu    schedule 29.12.2012
comment
Ваше последнее обновление показывает повреждение памяти ... Моя теория: структура платы находилась в памяти STACK, но больше не была, и обновление данных локальной переменной изменяет содержимое стека.   -  person benjarobin    schedule 29.12.2012
comment
я думаю, что нашел проблему. я создавал объект платы в стеке, не осознавая этого. было трудно найти настоящую причину, так как стек (вероятно) менялся где-то непредсказуемо. и в результате, когда данные по адресу b были перераспределены в стеке, указатель данных менялся на что-то, бог знает куда..   -  person Can Poyrazoğlu    schedule 29.12.2012
comment
Стек БУДЕТ меняться по мере того, как вы выполняете свою функцию, так что да, это вполне разумный эффект.   -  person Mats Petersson    schedule 30.12.2012
comment
@CanPoyrazoğlu, вы имеете в виду «я создавал объект доски в стеке без его инициализации»? Если бы вы могли подробнее рассказать о своей находке, было бы здорово. Например, что вы подразумеваете под «когда..b как перераспределено в стеке»? Я не вижу никакого перераспределения.   -  person zar    schedule 23.08.2016
comment
@zar Прошло больше 3,5 лет, я честно не помню.   -  person Can Poyrazoğlu    schedule 23.08.2016


Ответы (1)


Очевидно что-то/кто-то меняет свойство "данные" структуры платы.

Почему ? Я вижу только 3 причины:

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

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

  • Структура платы выделяется из кучи, затем освобождается, и, наконец, этот освобожденный указатель все еще используется: память кучи повреждена чем-то другим...

Мое предположение: второй пункт, который является частой ошибкой

Итак, простой вопрос: структура платы хранится в памяти HEAP или STACK?

person benjarobin    schedule 29.12.2012
comment
в моем коде нет ничего связанного с многопоточностью, это простой код. поверьте мне, многопоточность не имеет ничего общего, как я уже ясно сказал в вопросе. - person Can Poyrazoğlu; 29.12.2012
comment
@ user93353 Извините, не заметил, я слишком быстро прочитал вопрос ... Я отредактировал свой ответ. И простите за мой плохой английский... - person benjarobin; 29.12.2012
comment
да, ты был прав. я (по ошибке) размещал доску в стеке. см. мой последний комментарий под вопросом. - person Can Poyrazoğlu; 29.12.2012