Подтвердить что ты не робот

Что возможно в цикле for

Итак, сегодня я пошел на собеседование, и один из вопросов был следующим (контекст С#).

//Print the output for the following code:
for (int i = 10, j = 0; j <= 10; j++, i--)
{
    if (i > j)
        Console.WriteLine(j.ToString());
}

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

Итак, я думаю, мой вопрос сводится к этому.

  • Используют ли все языки, основанные на синтаксисе C, эту функциональность? IE: C, С++, Java, javascript и т.д.
  • Где этот синтаксис вытекает из?
  • Существуют ли какие-либо другие "не известные" структуры, которые может принимать цикл for?
  • Является ли код, подобный приведенному выше, считается плохой практикой, учитывая, как трудно читать?
  • Есть ли хорошие примеры реального мира, где такая структура требуется?
4b9b3361

Ответ 1

for (statement1; statement2; statement3)
{
     /* body */
}

(1) Сначала выполняется statement1.

(2) Далее выполняется statement2.

(3) Если оценка statement2 истинна, тело выполняется

(4) Выполняется statement3.

(5) Повторите шаг (2)

          |                  +<-----------------+
          |                  |                  ^
          V                  V                  |
 for (  (s1); -------->(s2 true? | false?);    (s3) )
 {                           |       |          ^
                             |       |          |
                             |       |          |
                             V       |          |
                          (body)-----|--------->+
 }                                   |
                                     |
                                     V
                                 (come out)

Структура, которую вы показали, имеет такую ​​же нормальную структуру, как указано выше. statement n может быть любым утверждением. В вашем примере вы разделили операторы запятой в statement1 и statement3. Вы можете отделить любое количество операторов операторами запятой.

Как правило, циклы for используются с statement1 с инициализацией, поскольку она выполняется только один раз. statement2 используется для проверки условия завершения цикла, потому что оценочное значение этого оператора используется для принятия решения о входе в тело разрыва. И statement3 используется для обновления переменной завершения цикла, поскольку она выполняется после тела. Но в целом они могут быть использованы любым способом.

Сначала statement1 есть i=10, j=0;, это инициализирует переменные. Далее в statement2 есть j <= 10, если это правда, тогда тело выполняется. После того, как тело выполнено, выполняется statement3, который является i--,j++. Цикл будет повторять 11 раз 0 до 10. Но будет печатать 5 раз, так как в одной точке i и j станет такой же, а if (i > j) будет оценивать false.

ИЗМЕНИТЬ Вот пример, где он может быть использован, не так много практического, но пример использования, чтобы проверить строку палиндрома.

  int i, j, n, flag;
  char str[128];

  printf ("\nEnter string: ");
  scanf ("%s", &str);
  n = strlen (str);


for (flag=1, i=n-1, j=0; j<n/2; j++, i--)
{
  if (str[i] != str[j])
  {
    flag = 0;
    break;
  }
}

if (flag)
 printf ("\n\"%s\" is a palindrome");
else
 printf ("\n\"%s\" is not a palindrome");

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

Ответ 2

  • Java и С# оба используют один и тот же синтаксис
  • Синтаксис, вероятно, связан с C/С++, который является "корнем" Java и С#
  • Да, вы также можете иметь нулевые инициализаторы и конечные условия для цикла for.
  • Независимо от того, действительно ли это плохая практика, зависит от того, как она используется. Вы можете создать довольно загадочный код, используя эту технику, однако это не значит, что при правильном использовании это вполне приемлемо.
  • Я сомневаюсь в этом!

Ответ 3

В цикле C и Java for вы можете указать неограниченное (или нулевое) количество инициализаторов, разделенных запятыми (одного и того же типа данных) и действий конца цикла.

Раздел инициализатора - это всего лишь один оператор java; Определения переменных java могут быть сгруппированы, если они одного типа, то есть:

int i = 0;
int j = 0;

эквивалентно:

int i = 0, j = 0;

Вы можете делать то, что вам нравится в конце цикла - любое количество операторов, разделенных запятыми.

Начиная с java 5, существует также синтаксис foreach, например:

List<String> list;
for (String element : list) {
    // do something with the variable element
}

Синтаксис работает с типами Iterable, который включает в себя массивы и коллекции.

Ответ 4

  • Java поддерживает это для структуры. В других языках, таких как C, вы можете иметь любое выражение вместо условия условия. Этот раздел не должен быть связан и может использовать разные переменные.

    for({declaration-clause}; {condition-clause}; {expression-clause})
    
  • Синтаксис - это просто расширение деклараций объявлений и выражений в C.

    int i = 10, j = 0; // a declaration
    j++, i--; // an expression.
    
  • Слишком много, чтобы упомянуть.

  • Это может быть плохая практика, если вы не можете определить, что означает код. В вашем случае вы смогли понять это, даже если бы вы не написали его таким образом.
  • Для цикла никогда не требуется . Вы всегда можете заменить его на цикл while, no.

Ответ 5

Согласно моему опыту и исследованию, этот тип "конструкции условия" очень часто встречается при обработке изображений, скажем (действительно, скажем), вам нужно сравнить пиксели между двумя изображениями (скажем, снова) противоположными направлениями. Или даже пересечь соседей в направлениях opp. Другой пример, в этом типе "конструкции условия", когда вам нужно преобразовать 32-битный бит в 24-бит или наоборот. (только то, что приращение будет битовым, как я = я + 4, j = j + 3).

Ответ 6

вывод: 0 9 8 7 6


  • Языки, основанные на синтаксисе C, реализуют эту функциональность.
  • Где этот синтаксис связан с c.
  • Одна часть, две части, три части, все могут исчезнуть. Не имеют части, цикл может работать правильно.
  • Это плохая практика.
  • Я не знаю.

Ответ 7

В ответ на 5 одно общее использование - это что-то вроде этого (в C):

for (size_t pos = 0, end = strlen(something); pos < end; ++pos) {
    if isspace((unsigned)(something[pos])) {
        puts("contains whitespace");
        break;
    }
}

вместо:

for (size_t pos = 0; pos < strlen(something); ++pos) { ... }

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

Конечно, вы могли бы написать это:

const size_t end = strlen(something);
for (size_t pos = 0; pos < end; ++pos) { ... }

Таким образом, нет строгого требования к дополнительной переменной, которая должна быть определена в инструкции for, и, возможно, есть крошечное преимущество в создании end const (или final) в любом случае, которое вы теряете, определяя pos и end вместе. Некоторые люди предпочитают, чтобы "переменные цикла" (в данном случае включая "константу цикла" ) для всех определялись в инструкции for, хотя, поскольку они "принадлежат" ему.

Плюс, прежде чем кто-то отметит это, в моем примере вам вообще не нужна индексация:

for (const char *ptr = something; *ptr; ++ptr) { 
    if isspace((unsigned)*ptr) { ... }
}

но мы можем притвориться, что у нас есть задача, в которой мы ищем итерацию с использованием вычисленной конечной точки...

Ответ 8

В контексте С# (который мой ответ будет учитывать только), нет никакого оператора запятой, как в С++ и C, поэтому технически ссылка на оператор запятой неверна для С#.

Но оператор С# for все еще был разработан, чтобы позволить конструкциям, которые люди уже знали из С++.

Точные правила можно найти в разделе раздела Инструкция for в Спецификации языка С#. Мы видим, что третий и последний "компонент" в операторе for (;;) определяется как оператор-выражение-список, а список-выражение-выражение определяется рекурсивным образом как список выражений операторов, разделенных символ , (запятая).

Итак, это объясняет часть j++, i--.

Мы также видим, что первая часть в for (;;) может быть либо локальная переменная-объявление, либо список-выражение-выражение, Первая может содержать запятую. Объявление int i = 10, j = 0; разрешено как независимый оператор (т.е. Не внутри for) и должно интерпретироваться как объявление локальной переменной.