Как использовать ? знак вопроса в цикле for в C?

Если i четно, for(int j = 0; j < m; j++)

В противном случае, если iнечетно, for(int j = m-1; j > 0; j--)

Я хотел бы объединить эти два условия следующим образом.

for( (i%2==0) ? (int j = 0; j < m; j++) : (int j = m-1; j > 0; j--))

Но, похоже, это не удалось.

Есть ли способ объединить два условия, используя ? или другой способ языка C?

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

ShadowRanger 19.09.2023 03:34

Таким образом нельзя использовать (тройной) оператор ?:. Просто сделайте очевидную/простую версию: if ((i % 2) == 0) { for (int j = 0; j < m; ++j) { /* do even */ } } else { for (int j = m - 1; j > 0; --j) { /* do odd */ } }

Craig Estey 19.09.2023 03:46

Если вам просто нужен вопросительный знак, вы можете сделать for(int i=0; i<n ??! i<n; i++).

Lundin 19.09.2023 14:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
129
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Нет, их нельзя комбинировать с условным оператором . Операндами условного выражения являются каждое выражение, возвращающее значение, а результатом условного выражения является одно значение.

Цикл for имеет форму for( init expression; condition expression; iteration expression) loop-body и принимает три выражения.

Вы пытаетесь вернуть какой-то трехэлементный кортеж (init, condition, iteration) выражений из тернарной системы, который будет служить в качестве выражений инициализации/условия/итерации цикла for, но вы не можете упаковать эти вещи, а затем распаковать их таким образом. Синтаксис просто в корне неверен.

Используйте if/else. Если вы хотите поделиться телом цикла, поместите его в функцию и вызывайте функцию из каждого цикла:

if (i % 2 == 0) {
  for (int j = 0; j < m; j++) {
    do_things(j);
  }
} else {
  for (int j = m-1; j > 0; j--) {
    do_things(j);
  }
}

'Было бы жаль, если бы do_things() требовалось множество дискретных переменных, которые присутствовали в вызывающей функции...

Fe2O3 19.09.2023 10:00

@ Fe2O3 Не уверен, в чем твоя точка зрения. Факторируйте свой код так, как вам нравится.

user229044 19.09.2023 13:55

Нет, вы не можете... Меня, вероятно, следует сослать в самые глубокие ямы ада за упоминание об этом, но «выражение утверждения» GCC можно было бы исказить и злоупотребить настолько, чтобы сделать то, что предлагает ФП. Да, теперь я вручную скопирую K&R 20 миллионов раз в качестве наказания. :-)

Andrew Henle 19.09.2023 23:33
Ответ принят как подходящий

Вы могли бы сделать что-нибудь хаотичное и запутанное, например следующее, но я бы не рекомендовал это делать. При этом ведется обратный отсчет от m-1 до 0, если i нечетное, и от 0 до m-1, если i четное. Обратите внимание, что исходный вопрос ведет обратный отсчет от m-1 до 1, и я предположил, что вы хотите от m-1 до 0, поэтому исправьте при необходимости.

Будьте осторожны с «неожиданными» входными значениями m, например. отрицательные, потому что в этом случае цикл может не завершиться, когда вы захотите.

#include <stdio.h>

int main()
{
    int i = 1;
    int m = 8;
    
    int start = i%2 ? m-1 : 0;
    int end = i%2 ? -1 : m;
    int delta = i%2 ? -1 : 1;
    
    for (int j = start; j != end; j += delta)
    {
        printf("j=%d\n", j);
    }

    return 0;
}
if iis odd, for(int j = m-1; j > 0; j--) ... Забавно, что ОП выбирает ответ «один на один».
Fe2O3 19.09.2023 04:29

jarmod, длинный цикл, а затем неопределенное поведение с экстремальными входными данными, такими как int i = 0; int m = -1;. j != end не является достаточным условием остановки.

chux - Reinstate Monica 19.09.2023 13:17

@ Fe2O3 Fe2O3 да, вы правы, но я предполагал, что исходный вопрос по ошибке завершил цикл раньше, когда i нечетно. Это была догадка. Возможно, это была хорошая догадка, я не знаю, но я написал решение, исходя из этого предположения. Я также точно указал, каковы были начальные/конечные значения, чтобы ОП мог решить, правильно ли это, и исправить при необходимости.

jarmod 19.09.2023 13:40

@chux-ReinstateMonica да, и спасибо. Я изменил ответ, добавив дополнительное предупреждение.

jarmod 19.09.2023 13:46

Не усложняйте цикл, считая в большую или меньшую сторону... Просто переведите счетчик цикла по мере необходимости:

void doit( int m, int i ) {
    // peculiar imbalance in OP's ranges :\
    // if i is odd, bail out BEFORE reaching 0th value
    m -= i%2;
    for( int j = 0; j < m; j++ ) {
        int k = i%2 ? m - j : j;  // ternary, and begin using 'k'

        printf( "%d ", k );
    }
    putchar( '\n' );
}

int main( void ) {
    doit( 15, 0 );
    doit( 15, 1 );

    return 0;
}

Результат:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
14 13 12 11 10 9 8 7 6 5 4 3 2 1

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

int main( void ) {

    for( int i = 0; i <= 1; i++ ) { // demonstrate both even and odd

        unsigned m = 10; // # of steps

        for( unsigned j = 0; j < m; j++ ) { // traverse range

            int k = i%2 ? m - j - 1: j; // descending or ascending

            printf( "%d ", k ); // Simulate processing
            /* more processing with this value */
        }

        putchar( '\n' );
    }

    return 0;
}

Результат:

0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0

(Изменено на unsigned, чтобы обойти проблему, поднятую @Chux)


Demonstrating effectiveness of this implementation: a ludicrous Celsius/Fahrenheit conversion:
int main( void ) {
    double temp = get_double( "Temperature: " );
    int i = get_int( "Is this Celsius(0) or Fahrenheit(1): " );

    for( unsigned m = 3, j = 0; j < m; j++ ) {
        switch( (i%2) ? m - j - 1: j ) {
            case 0:
                temp *= (i%2) ? 5 : 1.0/5;
                break;
            case 1:
                temp *= (i%2) ? 1.0/9 : 9;
                break;
            case 2:
                temp += (i%2) ? -32 : 32;
                break;
        }
    }

    printf( "%.2lf%s\n", temp, i%2 ? "C" : "F" );

    return 0;
}

Спасибо, это очень помогает. Я желаю вам всего наилучшего !!!!

ident 20.09.2023 01:14

Золотое правило, чтобы стать успешным программистом: не усложняйте вещи просто так. Пишите код максимально простым и читабельным способом.

Например, это очень читабельно, и поэтому его очень трудно улучшить дальше:

if (i % 2) // odd
{
  for(int j=m-1; j > 0; j--)
  {
    do_stuff_with(something[i][j]);
  }
}
else // even
{
  for(int j = 0; j < m; j++)
  {
    do_stuff_with(something[i][j]);
  }
}

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

// not really recommended
int start;
int end;
int mod;

if (i % 2) // odd
{
  start = m-1;
  end   = -1;
  mod   = -1;
}
else // even
{
  start = 0;
  end   = m;
  mod   = 1;
}

for(int j=start; j!=end j+=mod)
{
  do_stuff_with(something[i][j]);
}

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

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

ident 20.09.2023 01:15

Другие вопросы по теме