[Для протокола, я отредактировал этот ответ довольно значительно, так как он был принят и проголосовал. Это все еще говорит в основном то же самое, все же.]
Этот код глубоко, возможно, намеренно, запутывает. Он содержит узко предотвращенный экземпляр ужасного неопределенного поведения . В принципе невозможно определить, был ли человек, который создал этот вопрос, очень, очень умным или очень, очень глупым. И «урок», который может принести этот код для изучения или опроса о вас, а именно, о том, что унарный оператор плюс мало что делает, - безусловно, не является достаточно важным, чтобы заслужить такого рода диверсионное неверное направление.
Есть два запутанных аспекта кода, странное условие:
while(+(+k--)!=0)
и безумное заявление, которое оно контролирует:
k=k++;
Я собираюсь осветить вторую часть первой.
Если у вас есть такая переменная, kкоторую вы хотите увеличить на 1, C дает вам не один, не два, не три, а четыре различных способа сделать это:
k = k + 1
k += 1
++k
k++
Несмотря на эту награду (или, возможно, из-за этого), некоторые программисты запутываются и выкашивают такие искажения, как
k = k++;
Если вы не можете понять, что это должно делать, не волнуйтесь: никто не может. Это выражение содержит две разные попытки изменить kзначение ( k =часть и k++часть), и поскольку в C нет правила, чтобы сказать, какая из попыток модификации "выиграет", такое выражение формально не определено , что означает не только то, что у него нет определенного значения, но вся программа, содержащая его, является подозрительной.
Теперь, если вы посмотрите очень внимательно, вы увидите, что в этой конкретной программе строка на k = k++самом деле не выполняется, потому что (как мы увидим) условие управления изначально ложно, поэтому цикл выполняется 0 раз. , Поэтому эта конкретная программа не может фактически быть неопределенным - но это все-таки патологический заблуждение.
Смотрите также эти канонические SO ответы на все вопросы, касающиеся неопределенного поведения такого рода.
Но вы не спросили о k=k++роли. Вы спрашивали о первой запутанной части, +(+k--)!=0состоянии. Это выглядит странно, потому что это странно. Никто никогда не будет писать такой код в реальной программе. Так что нет смысла учиться понимать это. (Да, это правда, изучение границ системы может помочь вам узнать о ее тонкостях, но в моей книге есть довольно четкая грань между творческими, заставляющими думать исследованиями по сравнению с глупыми, оскорбительными исследованиями, и это выражение очень четко неправильная сторона этой линии.)
Во всяком случае, давайте рассмотрим +(+k--)!=0. (И после этого давайте забудем все об этом.) Любое подобное выражение следует понимать изнутри. Я полагаю, вы знаете, что
k--
делает. Он принимает kтекущее значение и «возвращает» его остальной части выражения, и он более или менее одновременно уменьшается k, то есть сохраняет количество k-1обратно k.
Но тогда что делает +? Это унарный плюс, а не бинарный плюс. Это как унарный минус. Вы знаете, что двоичный минус делает вычитание: выражение
a - b
вычитает б из а. И вы знаете, что унарный минус отрицает вещи: выражение
-a
дает вам минус. То, что +делает унарный , это ... в основном ничего. +aдает вам aзначение, после изменения положительных значений на положительные и отрицательных значений на отрицательные. Итак, выражение
+k--
дает вам все, что k--дал вам, то есть, kстарая ценность.
Но мы еще не закончили, потому что у нас есть
+(+k--)
Это просто берет то, что +k--дало тебе, и +снова относится к нему одинарно . Так что это дает вам все, что +k--дало вам, то, что k--дало вам, что было kстарой ценностью.
Итак, в конце концов, состояние
while(+(+k--)!=0)
делает то же самое, что и гораздо более обычное условие
while(k-- != 0)
Сделал бы. (Это также делает то же самое, что while(+(+(+(+k--)))!=0)могло бы сделать даже более сложное на вид условие . И эти скобки на самом деле не нужны; это также делает то же самое, while(+ + + +k--!=0)что и сделал бы.)
Даже выяснить, что такое «нормальное» состояние
while(k-- != 0)
делает это довольно сложно. В этом цикле происходит две вещи: поскольку цикл может выполняться несколько раз, мы собираемся:
- продолжать делать
k--, чтобы сделать все kменьше и меньше, но и
- продолжайте делать тело цикла, что бы это ни делало.
Но мы выполняем свою k--роль сразу же, прежде чем (или в процессе) решить, предпринять ли еще одно путешествие по циклу. И помните, что k--«возвращает» старое значение k, прежде чем уменьшать его. В этой программе начальное значение kравно 0. Так k--что "вернуть" старое значение 0, а затем обновить kдо -1. Но остальная часть условия != 0- но, как мы только что видели, в первый раз, когда мы проверили условие, мы получили 0. Таким образом, мы не будем совершать никаких циклов, поэтому не будем пытаться выполнить проблемное утверждение k=k++на всех.
Другими словами, в этом конкретном цикле, хотя я сказал, что «происходит что-то вроде двух вещей», оказывается, что вещь 1 происходит один раз, а вещь 2 - ноль раз.
В любом случае, я надеюсь, что теперь достаточно понятно, почему это плохое оправдание для программы приводит к выводу -1 в качестве окончательного значения k. Обычно я не люблю отвечать на вопросы викторины, подобные этим - это похоже на мошенничество - но в этом случае, поскольку я так громогласно не согласен со всем смыслом упражнения, я не возражаю.