Изучение операторов в C

Я изучал следующий фрагмент кода и пытался написать на бумаге значения, которые i и j получают на каждом шаге, но я не понимаю, почему на 4-м шаге значение j уменьшается с 3 до 2, так как нет оператора декремента ( насколько я понимаю):

#include<stdio.h>

int main() {

  int i, j, n;

  int v[] = {
    -7,
    29,
    76,
    8
  };

  n = sizeof(v) / sizeof(int);

  for (i = 0, j = 1; n > 1 && i < n;
    (v[i] > v[j]) && (v[i] = v[i] + v[j] - (v[j] = v[i])), i++, j = j < n - 1 ? --i, j + 1 : i + 1) 
       printf("i=%d j=%d \n", i, j);

  for (i = 0; i < n; i++) printf("%d\t", v[i]);

  printf("\n");

  return 0;

}
Output: 
i=0 j=1 
i=0 j=2 
i=0 j=3
i=1 j=2
i=1 j=3
i=2 j=3
i=3 j=4
i=3 j=5
i=3 j=6
-7      8       29

Пытался понять, как i и j получают свое значение.

Это противно j = j < n - 1 ? --i, j + 1 : i + 1

Elliott Frisch 21.11.2022 17:07

Я не уверен, что этот код стоит изучать. Если бы я столкнулся с этим кодом, первое, что я бы сделал, это упростил этот цикл for и разбил составные части на более легко усваиваемые операторы.

Robert Harvey 21.11.2022 17:07

gcc с усиленными предупреждениями считает, что этот код может демонстрировать неопределенное поведение. Это потому, что v[j] используется и назначается в одной и той же операции, и порядок их не определен.

pmacfarlane 21.11.2022 17:08

Я так и подозревал. Когда вы добьетесь этого ума, станет очень легко случайно вызвать UB.

Robert Harvey 21.11.2022 17:08

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

Robert Harvey 21.11.2022 17:09

Над j нет операции уменьшения, но есть присваивание j. На самом деле это единственный способ вообще изменить значение j. Во всяком случае, так оно и было бы, если бы поведение программы было определено иначе.

John Bollinger 21.11.2022 17:10

@Dan X Нет особого смысла исследовать этот глупый код.

Vlad from Moscow 21.11.2022 17:16

Если бы кто-то из моей команды написал подобное выражение цикла for, я бы серьезно задумался о его психическом состоянии :). А теперь серьезно: этот код не выглядит умным — и написание большего количества строк в одной строке или операторе не свидетельствует о хорошем программисте. Это прямо напротив. @RobertHarvey прав на 100%. Перепиши и найдешь ошибки

0___________ 21.11.2022 18:02
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
8
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Код недействителен:

  • v[i] = v[i] + v[j] - (v[j] = v[i]) присваивает v[j] и одновременно считывает из v[j]. Вы не можете этого сделать.
  • Когда j=4, то доступ к v[j] недействителен. v имеет 4 элемента, вы можете получить доступ к индексу 3.

почему на 4-м шаге значение j уменьшается с 3 до 2

Начиная с шага 3: i увеличивается i++, поэтому i=1. Тогда j просто присваивается значение 2 из ложной ветви троичного выражения. i + 1 равно 2, поэтому y=2.

> i=0 j=3 n=4
..., i++, j = j < n - 1 ? --i, j + 1 : i + 1
> i++         ->    i=1
..., j = j < n - 1 ? --i, j + 1 : i + 1
> j < n - 1   ->   3 < 3   -> false
j = i + 1
> i + 1       ->   1 + 1   -> 2
> j = 2
Ответ принят как подходящий

Я надеюсь, это поможет:

  1. Первая «часть» оператора for устанавливает начальные значения i и j (0 и 1 соответственно).

  2. Третья «часть» оператора for отвечает (в вашем примере кода) за все остальные изменения значений i и j. Эта часть представляет собой выражение с запятой (с тремя подвыражениями), которое оценивается слева направо. Эти подвыражения (в порядке оценки):

     (v[i] > v[j]) && (v[i] = v[i] + v[j] - (v[j] = v[i]))
    

Это означает: если (v[i] > v[j]), то дать v[j] предыдущее значение v[i] [часть: (v[j] = v[i])] и v[i] значение v[j] (часть: v[i] = v[i] + v[j] - (v[j] = v[i]), обратите внимание, что v[j] = v[i] оценивается как v [и]). Другими словами: если v[i] больше, чем v[j], то поменяйте местами значения v[i] и v[j].

     i++

Самая простая часть: увеличить значение i на единицу.

     j = j < n - 1 ? --i, j + 1 : i + 1

Здесь используется третичный оператор (?:). Если (j < n - 1) верно, то "--i, j+1" (другое выражение с запятой) оценивается (слева направо) и его значение (значение последней/правой части, т.е.: j+ 1) присвоен j. Другими словами: значение i уменьшается на единицу, а j увеличивается на единицу, если j меньше n-1. Если j не меньше n-1, то последняя часть третичного оператора i+1 присваивается j.

Кстати: я думаю, что последняя строка вашего вывода должна быть: «-7 8 29 76», а не «-7 8 29». Итак, этот фрагмент кода сортирует массив v[].

Поведение v[i] = v[i] + v[j] - (v[j] = v[i]) не определено стандартом C в соответствии с правилом C 2018 6.5 2, потому что оно одновременно изменяет значение v[j] и использует его значение без последовательности между этими двумя применениями.

Eric Postpischil 21.11.2022 18:40

@EricPostpischil: Вы, конечно, правы, но я пытался объяснить поведение данного образца кода, а не доказывать, что он может работать как программа на C в соответствии со стандартами.

rentoulis 22.11.2022 05:34

Спасибо за объяснение, я понимаю, что знаю, не мог понять, как j было присвоено значение, если (j<n-1) было ложным. Кроме того, да, код сортирует массив v[], поэтому вывод должен быть таким, как указано!

Dan X 22.11.2022 18:49

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