Действительно ли это - плохая идея использовать указатели в качестве инкременторов цикла вместо обычного “интервала i”?

import array
integerValue = array.array("I", 'y\xcc\xa6\xbb')[0]

Предупреждение: вышеупомянутое является решительно определенным для платформы. И "I" спецификатор и порядок байтов строки-> международное преобразование зависят от Вашей конкретной реализации Python. Но если Вы хотите преобразовать много целых чисел/строк сразу, тогда модуль массива делает это быстро.

7
задан 6 August 2009 в 20:17
поделиться

14 ответов

Моя единственная проблема заключается в том, что вам будет очень весело, если вы оставите * in * pc в цикле for. Упс? В более общем плане, немного сложнее определить разницу между переназначением указателя и изменением значения.

Однако (хотя у меня его нет под рукой), Сам Страуструп одобряет (см. Редактирование) итерацию указателя в языке программирования C ++ книга. В принципе, вы можете иметь довольно краткую реализацию сравнения строк между двумя массивами char с использованием арифметики указателей.

Короче говоря, я бы рекомендовал использовать такие указатели в режиме «только для чтения». Если вам нужно записать в массив, я бы использовал более традиционный i.

Это, конечно, все мои личные предпочтения.

Изменить: Stroustroup не поддерживает итерацию указателя OVER integer - он просто использует это в какой-то момент в книге,

8
ответ дан 6 December 2019 в 06:25
поделиться

В целом я придерживаюсь этого утверждения Бартоша Милевски в его большой свободно доступной книге по C ++ C ++ в действии .

Не используйте указатели, если нет другого пути. Я оставляю такую ​​оптимизацию компиляторам. Это настолько простое и распространенное использование, что очень маловероятно, что компиляторы не смогут понять, как оптимизировать этот вид кода.

И последнее из его книги:

Если ваш компилятор не может оптимизировать удобочитаемый, поддерживаемый версия алгоритма, и вы должны стать человеком-компилятором - купите новый компилятор! Никто больше не может позволить себе человеческих компиляторов. Так что пожалейте себя и своих товарищей-программистов, которым придется взглянуть на ваш код.

0
ответ дан 6 December 2019 в 06:25
поделиться

Иногда увеличение указателя в цикле выглядит довольно естественно. Взгляните на следующий код, который инициализирует текстуру DirectX из растрового изображения GDI +:

boost::uint8_t* pDest = static_cast<boost::uint8_t*>(d3dlr.pBits);
const boost::uint8_t* pSrc = static_cast<const boost::uint8_t*>(bitmap_data.Scan0);
for ( UINT i = 0; i < bmp_height; ++i, pSrc += bitmap_data.Stride, pDest += d3dlr.Pitch ) 
    memcpy(pDest, pSrc, bmp_width * BPP);

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

0
ответ дан 6 December 2019 в 06:25
поделиться

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

Область видимости переменной, находящейся в цикле, также может быть непереносимой.

0
ответ дан 6 December 2019 в 06:25
поделиться

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

В любом случае вам придется беспокоиться об тех же проблемах.

0
ответ дан 6 December 2019 в 06:25
поделиться

Это может сбивать с толку людей, не привыкших работать с указателями. Но просто нет смысла писать

for (int i=0; a[i]!=NULL; ++i){
    a[i] = ...;
}

вместо

for (aptr p=a; p!=NULL; ++i){
    *p = ...;
}

Используйте счетчик, когда они эквивалентны, и указатель, когда это имеет смысл.

2
ответ дан 6 December 2019 в 06:25
поделиться

Для C ++: Это совсем не плохая идея. В C ++ можно использовать указатели, аналогичные итераторам стандартной библиотеки. Вы даже можете использовать стандартные библиотечные алгоритмы, такие как std :: copy, с указателями. Также возможно реализовать std :: vector, используя указатели в качестве итераторов. Поэтому я предпочитаю использовать указатели вместо индексов.

1
ответ дан 6 December 2019 в 06:25
поделиться

ВСЕГДА плохая идея использовать конструкцию, которую вы не полностью понимаете. Это распространяется на людей, которым придется читать ваш код после того, как вы ... (я думаю, это следствие правила «Не будь умным программистом»)

В этом случае, если вы ДЕЙСТВИТЕЛЬНО понимаете, и полностью довольны конструкцией, то в ней нет ничего плохого ... Но обычно, если вы спрашиваете, плохая ли идея, то вам она не совсем удобна ...

8
ответ дан 6 December 2019 в 06:25
поделиться

Я не считаю проблематичным использовать указатель в качестве переменной цикла. Однако у меня есть несколько проблем с вашим примером:

char str[] = "Hello";
int strLength = strlen(str);

for (   char * pc = str;
        pc < str + strLength;
        pc++)
{
    *pc += 2;
}

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

Этот пример можно более четко и лаконично записать как:

char str[] = "Hello";

for (char *pc = str; *pc; ++pc) {
    *pc += 2;
}

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

0
ответ дан 6 December 2019 в 06:25
поделиться

Я согласен с ралу (и Милевски). Много лет назад компиляторы были тупыми и буквально каждый раз пересчитывали смещение массива (как мне сказали), так что было более эффективно использовать и самостоятельно увеличивать ptr. Однако через несколько лет они стали умнее (как говорит Милевски) и смогли преобразовать паттерн [i] в ​​ptr bumping сами. Вдобавок они могли использовать шаблон [i], чтобы немного развернуть цикл, но в то время не были достаточно умны, чтобы разглядеть уловку программиста bump-your-own-ptr. Теперь я не знаю, достаточно ли умен компиляторы в настоящее время, чтобы развернуть цикл с ручным накаткой простого указателя, возможно, так; но я понял из этого примера, что компилятор может делать более умные вещи, чем приходило мне в голову, и что лучшее, что я мог сделать, это прояснить свое намерение и уйти с его пути. Кроме того, я думаю, что другому программисту легче понять индексы, а это имеет большое значение.

1
ответ дан 6 December 2019 в 06:25
поделиться

"CakePHP выглядит как лучшее из PHP бродить по тонкому льду сложных манипуляций с указателями »(его термин), взгляните на прекрасную книгу Энди Кенига« C Traps and Pitfalls »( санированная ссылка Amazon )

Редактировать: Я забыл упомянуть одну вещь: я предпочитаю обычный стиль for (int i = 0; ..) просто потому, что это настолько укоренившаяся идиома, что любой может сразу увидеть, что вы делаете. Использование арифметики с указателями требует более глубокого изучения.

HTH

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

HTH

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

HTH

0
ответ дан 6 December 2019 в 06:25
поделиться

"CakePHP выглядит как лучшее из PHP но все же разрешено) преобразование строкового литерала в неконстантный char * , что позволяет компилировать ваш код. Однако вам нужен массив, в который вы можете записывать (и который предварительно инициализирован). Для этого используйте char str [] = "Hello!" .

Другая, незначительная ошибка заключается в том, что вы дважды перебираете строку: strlen пробегает символы, пока не находит '\ 0' , а затем вы выполняете опять то же самое. Было бы лучше, если бы вы сами проверили этот '\ 0' и вообще избегали вызова strlen .

Вот фиксированная версия вашего цикла:

char str[] = "Hello!";

for (char * pc = str; *pc != '\0'; pc++)
{
    *pc += 2;
}
4
ответ дан 6 December 2019 в 06:25
поделиться

Это в значительной степени идея итераторов STL, так что нет, это неплохая идея.

Канонический цикл, работающий с итераторами, выглядит примерно так:

for (iter cur = begin(); cur != end(); ++cur)

где iter может быть указателем или другим итератором. По сути, это то, как реализуются все стандартные библиотечные алгоритмы.

Однако лучший вопрос может заключаться в том, чего вы пытаетесь с его помощью достичь. Стандартная библиотека C ++ делает это, потому что обеспечивает аналогичный синтаксис для итерации по любой последовательности, а не только по массивам или другим контейнерам, которые определяют operator [] .

В некоторых случаях это лучше выражает ваши намерения. Иногда вам наплевать на счетчик цикла i , так почему он должен быть там?

Но в других случаях простой старый цикл for, там, где у вас есть доступ к переменной счетчика, имеет больше смысла. Делайте то, что лучше всего выражает ваши намерения.

3
ответ дан 6 December 2019 в 06:25
поделиться