Почему индексация 2D-массива с помощью арифметики указателей не аналогична использованию скобок [j], хотя в спецификации указано, что так и должно быть?

Изучая C, я наткнулся на это видео , на котором показана страница 82 спецификации C99 (правда, она датирована 2007 годом, может быть, это ревизия?).

Там утверждается, что любое выражение, индексирующее массивы с использованием индексов, например E1[E2], где один — pointer to object type, а другой — тип integer, идентично (*((E1)+(E2))) из-за правил преобразования, применимых к оператору +. Другими словами, использование арифметики указателей аналогично использованию квадратных скобок.

Мой вопрос: почему в моем коде этого не происходит? У меня есть двумерный массив символов, и я передаю его функции, что означает, что он неявно преобразуется в тип pointer to char array. Одна из операций по присвоению значений ее членам работает правильно, другая (которая в приведенном ниже коде закомментирована) нет и вместо этого обращается к, казалось бы, случайным адресам памяти.

int main(void) {
    char frame[S_HEIGHT][S_WIDTH];
    frame_init(frame);
    // ...
}

// ...

int frame_init(char (*frame)[S_WIDTH]){
    char ch = 'M';
    for(int i = 0; i < S_HEIGHT; i++){
        for(int j = 0; j < S_WIDTH; j++){
            *(*(frame + i) + j) = ch;    // this works! and so does (frame)[i][j] of course
         // *(frame + i)[j] = ch;        // this should be equivalent, but accesses wrong addresses
        }
    }
}

Конечно, если сделать распутывание вручную, соблюдая правила спецификации, то вы увидите, что

(frame)[i][j] == *(frame + i)[j] == *(*(frame + i) + j)

но работает только первое и третье, второе нет. Хотя так и должно быть, поскольку *(frame + i) имеет тип pointer to char и, следовательно, является допустимым выражением для индексации индексов. Компилируется и все.

Что с этим делать? Просто я использую более новую версию C, где это было изменено? Я пытался найти характеристики, но смог найти только это, за которое мне, черт возьми, придется заплатить. Нет ли бесплатного способа прочитать спецификацию?

Я очень ценю всех, кто находит время, чтобы прочитать и поделиться своими знаниями. Я люблю Си, и я люблю тебя тоже. С наилучшими пожеланиями, Мишель.

«Нет ли бесплатного способа прочитать спецификацию?» Вы можете получить черновые версии спецификации C бесплатно. Некоторые из них показаны в Где я могу найти текущие стандартные документы C или C++?

Weather Vane 20.04.2024 00:29

Но общее использование указателей, арифметика указателей и индексация указателей не изменились.

Weather Vane 20.04.2024 00:29

@WeatherVane большое спасибо за этот источник. Могу ли я спросить, каковы различия между окончательным проектом и официальной спецификацией, если таковые имеются? В основном это исправления формулировок и опечаток, или иногда в принимаемых решениях наблюдаются существенные различия?

Michele 20.04.2024 00:35

Я не знаю, какие именно различия могут быть, но если вам нужен черновик, используйте последнюю версию, которую сможете найти. Обратите внимание, что n2310.pdf является ранним проектом C23 от 2018 года, поэтому, AFAIK, он должен быть основан на выпущенном стандарте C17.

Weather Vane 20.04.2024 00:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
*(frame + i)[j]

означает:

*((frame + i)[j])

который:

frame[i + j][0]

Вы имели в виду:

(*(frame + i))[j]

что действительно эквивалентно:

frame[i][j]

Возможно, вас заинтересует https://en.cppreference.com/w/c/language/operator_precedence . * имеет приоритет 2, а [] имеет приоритет 1.

Нет ли бесплатного способа прочитать спецификацию?

Нет. Там, где встроенной версии стандарта в cppreference недостаточно, появляется мощная ссылка https://port70.net/~nsz/c/c11/n1570.html, которая технически содержит черновик C стандарт.

Это 100% так. У меня было ощущение, что это может быть проблема с приоритетом, но я не смог найти никакой документации и, должно быть, неправильно провел тесты при попытке добавить круглые скобки. Жаль, что cppreference так далеко в поиске Google. Я уже спрашивал другого доброго человека, который прокомментировал, но спрошу вас, если вы знаете, подробно: каких изменений мне следует ожидать между окончательным проектом спецификации и официальным выпуском? Кроме того, почему ссылка «могучая»? 😂 Огромное спасибо за ваш опыт и ссылки на источники!

Michele 20.04.2024 00:44
what changes should I expect between a specification's final draft, and the official release? Без понятия, стандарта не видел. Я ожидал, что на первой странице не будет слова «черновик», вот и все. why is the link "mighty"? Он часто используется на этом сайте, вы можете искать [language-laywer] с тегами [c]. А еще на сайте представлены все версии port70.net/~nsz/c
KamilCuk 20.04.2024 10:41

Определенно, Я бы сначала начал с объявления своих переменных, поскольку [i][j] — неизвестные факторы.

кадр[i][j] = [0]; другой путь

Другие вопросы по теме