Почему индексация в массиве начинается с нуля в C, а не с 1?
Почему индексация в массиве начинается с нуля в C, а не с 1?
Ответы:
В C имя массива - это, по сути, указатель [но см. Комментарии] , ссылка на область памяти и, таким образом, выражениеarray[n] ссылается на nэлементы ячейки памяти вдали от начального элемента. Это означает, что индекс используется в качестве смещения. Первый элемент массива точно содержится в той области памяти, на которую ссылается массив (0 элементов), поэтому его следует обозначить какarray[0] .
Для получения дополнительной информации:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
sizeof arrвозвращает размер объекта массива, а не размер указателя.
sizeofоператора или унарный &оператор или строковый литерал, используемый для инициализации массива, выражение с типом« массив » типа "преобразуется в выражение с типом" указатель на тип ", которое указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено. "
Этот вопрос был опубликован более года назад, но здесь идет ...
Хотя статья Дейкстры (ранее упоминавшаяся в теперь удаленном ответе ) имеет смысл с математической точки зрения, она не так актуальна, когда речь идет о программировании.
Решение, принятое проектировщиком спецификаций языка и базирующимся на нем, основано на решении дизайнеров компьютерных систем начать отсчет с 0.
Цитата из « Просьбы о мире » Дэнни Коэна.
Для любого основания b первые b ^ N неотрицательных целых чисел представлены ровно N цифрами (включая ведущие нули), только если нумерация начинается с 0.
Это можно проверить довольно легко. В базе-2 возьмем 2^3 = 8
8-е число:
111может быть представлен с использованием 3битов, в то время как 1000потребуется дополнительный бит (4 бита).
Адреса памяти компьютера имеют 2^Nячейки, адресуемые Nбитами. Теперь, если мы начнем считать с 1, 2^Nячейки будут нуждаться в N+1адресных строках. Дополнительный бит необходим для доступа ровно к 1 адресу. ( 1000в приведенном выше случае.). Другой способ решить эту проблему - оставить последний адрес недоступным и использовать Nадресные строки.
Оба являются неоптимальными решениями , по сравнению с начальным счетом в 0, который будет держать все адреса доступными, используя ровно Nадресные строки!
Решение начать отсчет с 0тех пор проникло во все цифровые системы , включая программное обеспечение, работающее на них, потому что это упрощает перевод кода в то, что может интерпретировать базовая система. Если бы это было не так, была бы одна ненужная операция перевода между машиной и программистом для каждого доступа к массиву. Это облегчает компиляцию.
Цитата из статьи:

a[b]реализовано как *(a+b)в ранних компиляторах. Даже сегодня вы можете написать 2[a]вместо a[2]. Теперь, если индексы не начинаются с 0, то a[b]превратились бы в *(a+b-1). Это потребовало бы 2 добавления на процессорах времени вместо 0, что означает половину скорости. Явно не желательно.
Потому что 0 - это расстояние от указателя на начало массива до первого элемента массива.
Рассматривать:
int foo[5] = {1,2,3,4,5};
Для доступа к 0 мы делаем:
foo[0]
Но foo разлагается на указатель, и вышеупомянутый доступ имеет аналогичный указатель арифметического способа доступа к нему
*(foo + 0)
В наши дни арифметика указателей используется не так часто. Еще тогда, когда это был удобный способ взять адрес и убрать X «целых» из этой начальной точки. Конечно, если вы хотите просто остаться на месте, просто добавьте 0!
Поскольку индекс на основе 0 позволяет ...
array[index]
... быть реализованным как ...
*(array + index)
Если бы индекс основывался на 1, компилятору нужно было бы сгенерировать:, *(array + index - 1)а это «-1» ухудшило бы производительность.
Потому что это сделало компилятор и компоновщик проще (легче писать).
Ссылка :
«... Ссылка на память по адресу и смещению представлена непосредственно в аппаратном обеспечении практически на всех компьютерных архитектурах, поэтому эта деталь конструкции в C упрощает компиляцию»
и
«... это упрощает реализацию ...»
Индекс массива всегда начинается с нуля. Предположим, базовый адрес равен 2000. Теперь arr[i] = *(arr+i). Теперь if i= 0это означает *(2000+0) равен базовому адресу или адресу первого элемента в массиве. этот индекс обрабатывается как смещение, поэтому индекс по умолчанию начинается с нуля.
По той же причине, по которой когда среда и кто-то спрашивает вас, сколько дней до среды, вы говорите 0, а не 1, а когда это среда, и кто-то спрашивает вас, сколько дней до четверга, вы говорите 1, а не 2.
Самым элегантным объяснением, которое я прочитал для нумерации с нуля, является наблюдение, что значения хранятся не в отмеченных местах на числовой строке, а в промежутках между ними. Первый элемент сохраняется от нуля до единицы, следующий - от одного до двух и т. Д. N-й элемент сохраняется от N-1 до N. Диапазон элементов может быть описан с использованием чисел с любой стороны. Отдельные предметы по договоренности описываются с помощью номеров под ними. Если каждому дан диапазон (X, Y), идентификация отдельных чисел с использованием числа, указанного ниже, означает, что можно идентифицировать первый элемент без использования какой-либо арифметики (это элемент X), но нужно вычесть один из Y, чтобы идентифицировать последний элемент (Y -1). Идентификация предметов с использованием числа, указанного выше, облегчит идентификацию последнего предмета в диапазоне (это будет предмет Y),
Хотя было бы не страшно идентифицировать предметы на основе числа над ними, определение первого предмета в диапазоне (X, Y) как того, что выше X, обычно получается более приятным, чем определение его как нижнего (X +). 1).
Техническая причина может быть вызвана тем фактом, что указатель на область памяти массива является содержимым первого элемента массива. Если вы объявляете указатель с индексом единицы, программы обычно добавляют это значение единицы к указателю, чтобы получить доступ к содержимому, которое, конечно, не то, что вам нужно.
Попробуйте получить доступ к пиксельному экрану, используя координаты X, Y на основе матрицы 1. Формула очень сложная. Почему это сложно? Поскольку вы в конечном итоге преобразуете координаты X, Y в одно число - смещение. Почему вам нужно конвертировать X, Y в смещение? Потому что так организована память внутри компьютеров, как непрерывный поток ячеек памяти (массивов). Как компьютеры работают с элементами массива? Использование смещений (смещения из первой ячейки, модель индексации с нуля).
Поэтому в какой-то момент кода, который вам нужен (или необходим компилятор), нужно преобразовать формулу с 1 базой в формулу с 0, потому что именно так компьютеры работают с памятью.
Предположим, что мы хотим создать массив размером 5
int array [5] = [2,3,5,9,8],
пусть 1-й элемент массива направлен в местоположение 100,
и пусть мы считаем, что индексирование начинается с 1, а не с 0.
Теперь мы должны найти местоположение 1-го элемента с помощью индекса
(помните, что расположение 1-го элемента равно 100),
поскольку размер целого числа 4-битный,
поэтому -> с учетом индекса 1 позиция будет
размером of index (1) * размер целого числа (4) = 4,
поэтому фактическая позиция, которую он нам покажет,
100 + 4 = 104
что неверно, потому что начальное местоположение было в 100.
это должно указывать на 100, а не на 104,
это неправильно,
теперь предположим, что мы взяли индексирование с 0,
тогда
позиция 1-го элемента должна быть
размером индекса (0) * размер целого числа (4) = 0,
поэтому ->
местоположение 1-го элемента равно 100 + 0 = 100,
и это было фактическим местоположением элемента,
поэтому индексация начинается с 0;
Я надеюсь, что это прояснит вашу точку зрения.
Я из происхождения Java. Я представил ответ на этот вопрос на диаграмме ниже, которую я написал на листе бумаги, который говорит само за себя
Основные шаги:
Примечание : блоки, показанные на изображении, являются представлением памяти
Прежде всего вам нужно знать, что массивы внутренне рассматриваются как указатели, потому что «имя самого массива содержит адрес первого элемента массива»
ex. int arr[2] = {5,4};
Предположим, что массив начинается с адреса 100, поэтому первый элемент элемента будет по адресу 100, а второй теперь будет по адресу 104. Учтите, что если индекс массива начинается с 1, то
arr[1]:-
это может быть записано в выражении указателей как это-
arr[1] = *(arr + 1 * (size of single element of array));
рассмотрим размер int 4 байта, теперь,
arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);
как мы знаем, имя массива содержит адрес его первого элемента, поэтому теперь arr = 100,
arr[1] = *(100 + 4);
arr[1] = *(104);
который дает,
arr[1] = 4;
из-за этого выражения мы не можем получить доступ к элементу по адресу 100, который является официальным первым элементом,
Теперь рассмотрим индекс массива, начинающийся с 0, поэтому
arr[0]:-
это будет решено как
arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);
теперь мы знаем, что имя массива содержит адрес его первого элемента, поэтому
arr[0] = *(100);
который дает правильный результат
arr[0] = 5;
поэтому индекс массива всегда начинается с 0 в c.
справка: все подробности написаны в книге «Язык программирования С Брайана Кернингхана и Денниса Ричи»
В массиве индекс сообщает расстояние от начального элемента. Итак, первый элемент находится на расстоянии 0 от начального элемента. Итак, поэтому массив начинается с 0.
Это потому, что addressон должен указывать вправо elementв массиве. Давайте предположим, что массив ниже:
let arr = [10, 20, 40, 60];
Давайте теперь рассмотрим начало адреса 12и размер elementbe 4 bytes.
address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24
Если это не так zero-based , технически наш первый адрес элемента в arrayбудет 16неправильным, поскольку он находится 12.
Имя массива - это постоянный указатель, указывающий на базовый адрес. Когда вы используете arr [i], компилятор обрабатывает его как * (arr + i). Поскольку диапазон int равен от -128 до 127, компилятор считает, что от -128 до -1 отрицательные числа и от 0 до 128 являются положительными числами. Поэтому индекс массива всегда начинается с нуля.
intТипа требуется для поддержки по меньшей мере , 16-битный диапазон, и на большинстве систем эти дни поддерживает 32 бита. Я думаю, что ваша логика ошибочна, и ваш ответ действительно не улучшается по сравнению с другими ответами, уже предоставленными другими людьми. Я предлагаю удалить это.