unixforum.org
Форум для пользователей UNIX-подобных систем
C: Массив и отрицательный индекс
C: Массив и отрицательный индекс
Сообщение Janik » 17.07.2013 17:46
Re: C: Массив и отрицательный индекс
Сообщение NickLion » 17.07.2013 19:18
Re: C: Массив и отрицательный индекс
Сообщение Janik » 17.07.2013 19:43
Re: C: Массив и отрицательный индекс
Сообщение drBatty » 17.07.2013 21:20
просто написано по разному. a[i] пишут исключительно для удобства понимания.
ЗЫЖ в C++ это не совсем эквивалентно из-за перезагрузки операторов.
Скоро придёт
Осень
Re: C: Массив и отрицательный индекс
Сообщение Janik » 17.07.2013 21:58
Re: C: Массив и отрицательный индекс
Сообщение drBatty » 17.07.2013 22:13
дык в ваших интересах не получать канделябром по голове 😉
Опасность такого кода в том, что он легко проходит все тесты, и ломается исключительно в продакшене. В самый ответственный момент ЧСХ.
Причём дело вовсе не только в рандомном результате, ваш быдлокод может ВСЁ завалить. Вот пруф:
Скоро придёт
Осень
Re: C: Массив и отрицательный индекс
Сообщение BratSinot » 08.09.2013 21:26
Re: C: Массив и отрицательный индекс
Сообщение NickLion » 08.09.2013 22:10
Re: C: Массив и отрицательный индекс
Сообщение Rootlexx » 08.09.2013 22:11
Re: C: Массив и отрицательный индекс
Сообщение drBatty » 09.09.2013 07:48
Скоро придёт
Осень
Re: C: Массив и отрицательный индекс
Сообщение NickLion » 09.09.2013 10:03
Разрешены ли отрицательные индексы массива в C?
7 ответов
это правильно. Из C99 §6.5.2.1 / 2:
определение индекса оператор [] является то, что E1[E2] является идентично (*((E1)+(E2))).
нет магии. Это эквивалентность 1-1. Как всегда, когда разыменования указателя (*), вы должны быть уверены, что он указывает на действительный адрес.
но это было бы так:
это, однако, необычно использовать отрицательный индекс.
звучит нормально для меня. Однако это был бы редкий случай, когда вам это было бы законно нужно.
что, вероятно, было то, что arr указывал на середину массива, следовательно, делает arr[-2] указывая на то, что в исходном массиве, не выходя за пределы.
Я не уверен, насколько это надежно, но я просто прочитал следующее предостережение о отрицательных индексах массива в 64-битных системах (предположительно LP64):http://www.devx.com/tips/Tip/41349
Я знаю, что на вопрос ответили, но я не мог удержаться, чтобы не поделиться этим объяснением.
Я помню принципы разработки компилятора, Предположим, что A-массив int, а размер int равен 2, & Базовый адрес для a-1000.
это объяснение также является причиной того, почему отрицательные индексы в массивах работают в C.
т. е. если я подключусь к a[-5] это даст мне
он вернет мне объект на расположение 990. По этой логике мы можем получить доступ к отрицательным индексам в массиве в C.
о том, почему кто-то хочет использовать отрицательные индексы, я использовал их в двух контекстах:
имея таблицу комбинаторных чисел, которая сообщает вам гребень[1] [-1] = 0; вы всегда можете проверить индексы перед доступом к таблице, но таким образом код выглядит чище и выполняется быстрее.
поставив centinel в начале таблицы. Например, вы хотите использовать что-то вроде
Индексный оператор []
Синтаксис
Remarks
Постфиксное выражение (которое также может быть первичным выражением), за которым следует оператор подстрочного индекса [], указывает индексирование массива.
Сведения об управляемых массивах в C++/CLI см. в разделе массивы.
Адрес, полученный в результате выражения, не может быть равен E2 байтам из адреса E1. Вместо этого адрес масштабируется, чтобы дать следующий объект в массиве E2. Пример:
Индексное выражение также может иметь несколько индексов, как показано ниже:
Выражения с несколькими индексами ссылаются на элементы многомерных массивов. Многомерный массив — это массив, элементы которого сами являются массивами. Например, первый элемент трехмерного массива является двумерным массивом. В следующем примере объявляется и инициализируется простой двухмерный массив символов.
Положительные и отрицательные индексы
Отрицательный индекс в последней строке может привести к ошибке во время выполнения, так как он указывает на позицию адреса 256 int ниже, чем у источника массива. Указатель midArray инициализируется в середину intArray ; таким образом можно (но опасно) использовать для него как положительные, так и отрицательные индексы массива. Ошибки индексов массивов не создают ошибки времени компиляции, но дают непредсказуемые результаты.
Оператор индекса коммутативен. Поэтому массив выражений [index] и индекс [Array] гарантированно эквивалентны при условии, что оператор индекса не перегружен (см. раздел перегруженные операторы). Программисты чаще всего используют первую форму, но вторая форма также правильна.
Отрицательный индекс в массиве c
C++ : способ обращаться к отрицательным индексам в массиве
Здравствуй, сообщество CodeForces!
1) Бояниста ли идея? Существуют ли другие пути обратиться к отрицательному индексу массива?
2) Есть ли подводные камни у этого метода? Чем это может быть плохо?
На этом все, спасибо за внимание.
Надурить компилятор это хорошо, но будь в С++ какая-то проверка на выход за границы массива — это все просто получало бы RTE.
Для двумерных и более многомерных массивов придётся на нижних уровнях заполнять целые массивы вашими сдвинутыми указателями, а так — вполне себе нормальная идея. Она имеет право на существование, если хорошо понимать реальные границы «массива», который вы таким образом реализуете, что в общем и так всегда надо делать.
В посылке, которую я привел в качестве примера, необходим был двумерный массив. Вроде особых сложностей не возникло. Просто надо помнить, что двумерный массив — это массив массивов.
Как уже написали ниже, можно сделать шаблонную обертку, вот её пример:
Upd: ну и здесь есть memory leaks, надо добавить в деструктор удаление, но на олимпиадах не очень страшно.
Upd: отредактировал код после замечания.
Можно написать T buf[to — from + 1]; раз уж они зачем то шаблонные параметры
Спасибо, действительно, так проще.
Шаблонные, чтобы при объявлении писать не
По-моему, второй вариант менее затратен(по написанию):)
1) Да. Писали про это тут давно уже. Да и самому нетрудно догадаться.
2) Нет. Ничем. Главное знать точные границы.
UPD. Еще один подводный камень: не стоит так реализовывать массив вида arr[5..10], т.к. наш вспомогательный указатель будет в таком случае указывать на отрицательный элемент массива, а такие элементы не определены (читай главу 5.4 книги Кернигана и Ритчи). С отрицательным правым индексом ситуация аналогичная.
наш вспомогательный указатель будет в таком случае указывать на отрицательный элемент массива, а такие элементы не определены
А в чем проблема? В указателе невалидный адрес, ну ничего страшного. Пока мы не пытаемся разыменовать его. А если попытаемся, то это можно понимать как обычный себе выход за пределы массива.
Проблема в том, что по стандарту поведение не опредлено и оптимизатор может попробовать это использовать
Неопределённое поведение возникает в момент разыменования указателя, а не тогда, когда в указатель записывают плохой адрес. Иначе бы даже такой код приводил бы к неопределённому поведению:
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined
Почему C поддерживает отрицательные индексы массива?
Из этого поста в SO ясно, что C поддерживает отрицательные индексы.
Зачем поддерживать такое потенциальное нарушение памяти в программе?
Разве компилятор не должен выдавать предупреждение «Отрицательный индекс» хотя бы? (использую GCC)
Или этот расчет выполняется во время выполнения?
РЕДАКТИРОВАТЬ 1: Кто-нибудь может намекнуть на его использование?
РЕДАКТИРОВАНИЕ 2: для 3.) Использование счетчиков циклов в [] массивов/указателей указывает расчет индексов во время выполнения.
ОТВЕТЫ
Ответ 1
Вот пример использования.
Фильтр Infinite Impulse Response частично вычисляется из последних предыдущих выходных значений. Как правило, будет существовать некоторый массив входных значений и массив, где должны быть размещены выходные значения. Если текущий выходной элемент y i, тогда y i может быть рассчитан как y i= a 0 • x i + a 1 • x i-1 + a 2 • y i-1 + a 3 • y i-2.
Естественным способом написания кода для этого является что-то вроде:
Ответ 2
Расчет выполняется во время выполнения.
Отрицательные индексы не обязательно должны вызывать нарушение и использовать их.
Ответ 3
Зачем поддерживать такое потенциальное нарушение памяти в программе?
Поскольку он следует за арифметикой указателя и может быть полезен в определенном случае.
Не должен ли компилятор выдавать предупреждение об отрицательном индексе? (я использую GCC)
Или этот расчет выполняется во время выполнения?
Да, расчет выполняется во время выполнения.
Ответ 4
Разрабатывая ответ Таймона:
теперь отлично. Я не видел хорошего использования отрицательных индексов, но почему стандарт должен исключать его, если он вообще неразрешим, указываете ли вы за пределами допустимого диапазона.
Ответ 5
Ответ 6
OP: Почему поддержка. потенциального нарушения памяти?
OP. вывести предупреждение об отрицательном индексе.
OP. расчет, выполненный во время выполнения?
OP: намек на его использование?
Пример: один обрабатывает точку в массиве точек (Pt) и хочет определить, является ли промежуточная точка кандидатом для удаления, поскольку она является совместно инцидентом. Предположим, что вызывающая функция уже определила, что Mid не является ни первой, ни последней точкой.
Ответ 7
Ответ 8
Пример использования отрицательных индексов массива.
Я использую отрицательные индексы для проверки протоколов сообщений. Например, один формат протокола выглядит так:
или, в равной степени действительный:
Параметр f является необязательным и должен содержать один символ, если он указан.
Теперь я проверяю, введено ли f (здесь используется отрицательный индекс массива):
Обратите внимание, что я исключил проверку ошибок и другой код, который не имеет отношения к этому примеру.




