Обмен значениями двух переменных без использования третьей переменной в C?

Я нашел следующий фрагмент кода:

#include <stdio.h>

int main(void) {
    int x=10,y=15;
    x=x+y-(y=x);
    printf("x=%d y=%d",x,y);
    return 0;
}

Это на самом деле меняет местами переменные

Кто-нибудь может объяснить мне, как код меняет местами переменную?

Я думал, что скобка будет выполняться сначала, а затем выражение приводит к

x=x+y-y;

3 ответа

Решение

Этот алгоритм не работает, потому что он вызывает неопределенное поведение в этой строке:

x=x+y-(y=x);
    ^  ^

Вы модифицируете y а также используя его значение в той же точке последовательности, как в разделе 6.5 проекта стандарта C99:

Между предыдущей и следующей точкой последовательности объект должен иметь свое сохраненное значение, измененное не более одного раза путем оценки выражения.72) Кроме того, предыдущее значение должно быть только для чтения, чтобы определить значение, которое будет сохранено.

Существует также вопрос неопределенного поведения, так как порядок вычисления подвыражений не определен:

Группировка операторов и операндов указывается синтаксисом.74) За исключением случаев, указанных далее (для операторов function-call (), &&, ||,?: И запятых), порядок вычисления подвыражений и порядок в какие побочные эффекты имеют место, оба не определены.

В этом случае, если вы использовали clang это дало бы следующее предупреждение:

warning: unsequenced modification and access to 'y' [-Wunsequenced]
x=x+y-(y=x);
    ~   ^

насколько я могу сказать по умолчанию. Вы можете получить подобное предупреждение от gcc используя -Wall,

Есть несколько вопросов SO, которые охватывают, как поменять местами без временной, например, Замена двух переменных без использования третьей переменной.

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

  1. оценивать y = xи сохранить значение в y, В этом случае, x еще 10, и y теперь также 10. Само выражение оценивается как 10 (левая часть присваивания).
  2. оценивать x = x + y - (y = x), что приравнивается к x = x + y - 10, x а также y оба 10, так что это x = 10 + 10 - 10, так x сейчас 10

Сейчас, x а также y и 10, и первоначальное значение 15 теперь потеряно.

Изменить: насколько это может поменяться, это может быть связано с оптимизацией:

  1. оценивать y = x, но не храните значение в y еще. y затем все еще содержит значение 15, в то время как выражение присваивания оценивается в 10.
  2. Сейчас, x = x + y - 10 оценивает x = 10 + 15 - 10, давая правильное значение.

Оба сценария верны, но дают разные результаты.

Я думал, что скобка будет выполняться первым...

Это неверное предположение. Скобки влияют на приоритет операторов в выражении. Они не указывают порядок исполнения. В

 a = b + c + (d * e);

вполне может быть, что b + c вычисляется раньше (d * e), Или не может. Стандарт языка C оставляет порядок вычисления подвыражения неопределенным. Код, который вы опубликовали, вызывает неопределенное поведение из-за y быть прочитанным и записанным без промежуточной точки последовательности. Еще раз обратите внимание, что скобки не вводят точки последовательности (точка с запятой делает).

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