Разве плохо обращаться к элементам массива доступа через арифметику указателей вместо оператора []?

12

Я только начал учиться программировать на C, и чтобы улучшить мое понимание указателей и массивов, я попытался ссылаться на элементы массива, не создавая вообще никакого указателя:

for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}

Весь код компилируется и работает без нареканий.

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

Таким образом, вместо того, чтобы хранить и извлекать адрес массива с помощью указателя, является ли плохой практикой программирования использовать адрес массива напрямую, как показано выше?

Нико Гамбт
источник
Использование printf "[%d][%d] = %d\n", k1, k2, array[k1] [k2]));позволит избежать арифметики указателя и будет проще для понимания.
Каспер ван ден Берг
1
Хаха, ты меня понял. Я сделал это только в качестве эксперимента, чтобы лучше понять, как работают указатели и массивы.
Нико Гамбт
Арифметика указателей на самом деле примерно на 30% быстрее, чем при использовании индексов массива.
Энди

Ответы:

16

Это «плохо» только в той степени, в которой это менее читабельно. a[x]это то же самое *(a+x), так что нет никакой разницы в эффективности или поведении (на самом деле, x[a]также будет работать). Просто это, a[x]как правило, намного более интуитивно понятно для нас, людей.

Но это не значит, что читаемость не имеет большого значения. Чтобы увидеть, насколько они велики, подумайте, как бы вы «прочитали» эти два выражения, если бы увидели их в коде:

  • *(a+x)= "То, на что указывает сумма указателя aи целого числа x"
  • a[x]= " xТой член массива a"

Точно так же, когда вам нужно обратиться к адресу элемента массива:

  • (a+x)= "Сумма указателя aи целого числа x"
  • &a[x]= "Адрес xth-го элемента массива a"

В большинстве случаев []версии легче понять, когда вы смотрите на нетривиальный код, работающий с несколькими различными массивами (особенно с массивами массивов). Вот почему []оператор существует в первую очередь.

PS Делать такие вещи строго как учебное упражнение - очень хорошая идея. Важно понимать, что массивы - это просто указатели и смещения.

Ixrec
источник
Эта. Спасибо. Я только что понял в глубине души, что я действительно хочу знать, является ли или нет, когда есть необходимость обратиться к адресу любого элемента массива, а затем обратиться к адресу другого элемента, а затем еще одного, это все еще плохо НЕ использовать указатель и вместо этого использовать массив напрямую, как я? Этот мой вопрос было очень сложно определить, поэтому я не набрал его в OP. Во всяком случае, так как я не спрашивал, ваш ответ удовлетворительный.
Нико Гамбт
1
@NikoGambt Вы всегда можете задать другой вопрос =)
Ixrec
1
Что ты имеешь в виду только в той степени ...? Весь смысл языков программирования состоит в том, чтобы облегчить чтение кода для людей. Если бы нас это не волновало, то мы бы все писали оп-коды в шестнадцатеричном формате.
Соломон Медленный
2
Массивы - это не указатели, а просто неявное указание на указатели.
CodesInChaos
4

Да, это плохая практика, но не по причинам неэффективности.

Оператор Array использует арифметику указателя под капотом, поэтому они одинаково эффективны.

Проблема с арифметикой указателей в том, что она очень подвержена ошибкам и труднее для чтения.

Правило большого пальца: не используйте арифметику указателя без необходимости.

user694733
источник
1
Поскольку в любом случае он использует арифметику указателей, разве это не означает, что указатели также одинаково подвержены ошибкам и их трудно читать?
Нико Гамбт
1
Компиляторы @NikoGambt достаточно хорошо умеют делать арифметику указателей и редко допускают «ошибки»; как следствие, программисты будут ошибаться с неприятными ошибками.
Каспер ван ден Берг
@KaspervandenBerg Да, я согласен. Тем не менее, меня интересуют ошибки, допущенные программистами, и я просто не совсем уверен, является ли плохая практика программирования делать то, что я делал там выше, в случаях, когда необходимо обратиться к адресу массива , если такие случаи существуют.
Нико Гамбт
1
@NikoGambt Написание чего-то, что является менее читабельным для целей производительности, почти всегда является плохой практикой, но написание чего-то, что является менее читабельным без выгоды, является однозначно плохой практикой.
Нил
@Neil Мой маленький эксперимент не бесполезен. Сделав это, я узнал, что компилятор, похоже, создает массив указателей для ссылки на многомерный массив. Однако, поскольку вы сказали, что удобочитаемость важнее производительности, я думаю, это все еще плохая практика программирования.
Нико Гамбт
0

Охладите свое обучение, вы только что обнаружили один из маленьких скороговорок. Вы делаете не арифметику указателей над массивом, а массив указателей. Делать арифметику указателей на массивах невозможно. Массив распадается на указатель, но сам по себе не является указателем. Что у вас есть (см. Комментарий cmaster)

int *array[]; //This is a array to pointers of type *int. 

array[k1] + k2; //This is pointer arithmetic on one pointer stored in the array  

Разыменование этого указателя дает значение, на которое указывает только что рассчитанный вами указатель. Как правило, нет смысла делать то, что вы делаете. Но вы можете линеаризовать массив, а затем шагать по нему, вот так.

int array[y_dim*x_dim]; 
int index = x_dim*y + x; 
array[index]; //Gives you the element in x, y!

Страйд у нее есть x_dim. Надеюсь, мой ответ проясняется!

fhtuft
источник
Пока не ясно , из OP использует ли это , или . Любое из этих трех определений может использоваться с кодом в OP. int* array[ROW];int array[ROW][COLUMN];int (*array)[COLUMN];
cmaster - восстановить монику
да, я знаю об этом, мой ответ немного неуклюж по этому вопросу. Я исправляю это, спасибо!
fhtuft