Почему я получаю EXC_BAD_ACCESS, даже если указатель кажется действительным?

#c #arrays #pointers #exc-bad-access

#c #массивы #указатели #исключение-bad-access

Вопрос:

Я начинаю с целочисленного массива test[] , который представляет набор изображений. Первые два элемента test[] — это высота и ширина первого изображения. Следующие четыре (height*width) элемента являются значениями пикселей. Следующие шесть представляют следующее изображение и так далее.

Моя цель — получить доступ к изображениям через объекты изображений, не дублируя ничего в test[] массиве. Я пытаюсь сделать это через ImageSet::import .

 int main(){
    int test[] = {2,2,1,2,3,4,
                  2,2,4,5,6,7,
                  2,2,9,8,0,9};
    ImageSet set = ImageSet();
    set.import(test); //ImageSet::import
    return 0;
}
  

ImageSet::import использует переменную курсора для сохранения начального индекса следующего изображения.
он вызывает Image::import чтение этих данных в объект изображения. Данные для этого конкретного изображения должны начинаться с адреса amp;data[cursor] .

 void ImageSet::import(int data[]){
    int cursor = 0;
    for(int i = 0; i < NUM_SRC_IMAGES; i  ){
        int height = data[cursor];
        int width = data[cursor 1];
        source_[i].import(amp;data[cursor]); //this is Image::import
        cursor  = height * width   2;
    }
}
  

Внутри image::import я получаю неверный доступ при попытке чтения data[0] . Согласно отладчику, data[] указывает на правильное значение 2, но EXC_BAD_ACCESS все равно выдается, когда я пытаюсь получить это значение через data[0] .

 void Image::import(int data[]){
    height_ = data[0]; //the problem occurs right here
    width_ = data[1];
    matrix_ = amp;data[2];
}
  

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

Спасибо!

Комментарии:

1. Вы пробовали передавать его как source_[i].import(data cursor) ?

2. Пожалуйста, полную программу. sscce.org

3. Добавьте пару операторов печати после for(int i = 0; i < NUM_SRC_IMAGES; i ){ для печати i и cursor , чтобы убедиться, что вы не пытаетесь получить доступ к памяти сверх того, что вы должны.

4. Проблема с чтением данных [0] или проблема с записью height_?

5. Почему вы не используете const? Почему вы не используете итераторы? Вы уверены, что я

Ответ №1:

Учитывая ограниченную информацию в вопросе, я могу предложить следующее:

  1. попробуйте изменить import на ImageSet::import(const int* data, size_t size) или … предпочтительно, ImageSet::import(const int (amp;data[18])) — это позволяет получить четкую ссылку в отличие от data[], которые могут быть оптимизированы при некоторых обстоятельствах. Последний также явно указывает вашим коллегам-разработчикам, что это ссылка на массив (в отличие от указателя). То же самое для Image::import .

  2. В Image::import распечатайте значение data (т. Е. amp;data[0] ) — это позволит вам узнать, действителен ли адрес.

  3. в конце цикла в ImageSet::import распечатайте значение cursor .

Я предполагаю, что в третьем цикле или около того значение cursor становится слишком большим, больше 18. Я не знаю, каковы ваши намерения… но эта cursor = 3 4*2 логика (в качестве примера) выглядит действительно подозрительной.

Ответ №2:

Я предполагаю, что на этапе оптимизации компилятор перестраивает ваш цикл на

 for(int i = 0; i < NUM_SRC_IMAGES; i  ){
    source_[i].import(amp;data[cursor]); //this is Image::import
    int height = data[cursor];   // -> would also crash, but you don't see it because import crashes earlier
    int width = data[cursor 1];
    cursor  = height * width   2;
}
  

И поскольку вы определили NUM_SRC_IMAGES слишком большими, вы читаете после окончания теста.

Кстати, вам также следует подумать об использовании STL, подобного стилю итератора, а затем вызвать set.import(begin(test), end(test)); Абстрагируясь от базового типа, вы могли бы читать данные из любого контейнера. И вы можете свериться с концом, чтобы никогда не читать дальше конца.