Как заканчивается этот цикл и являются ли результаты детерминированными?

#c #iteration

#c #итерация

Вопрос:

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

Причина, по которой я сбит с толку, заключается в:

 1. `someArray` is of size 2, but clearly, the loop goes till size 3,
2. The value is deterministic and it always exits `someNumber` reaches 4
  

Может кто-нибудь, пожалуйста, объяснить, как это происходит?

Код печатался неправильно, когда я заключил в угловые скобки <> названия библиотек include.

 #include <stdlib.h>
#include <time.h>
#include <stdio.h>

int main() {
    int someNumber = 97;
    int someArray[2] = {0,1};
    int findTheValue;

    for (findTheValue=0; (someNumber -= someArray[findTheValue]) >0; findTheValue  ) {

    }
        printf("The crazy value is %d", findTheValue);
    return EXIT_SUCCESS;
}
  

Комментарии:

1. Действительно, я бы предположил, что значение findTheValue будет = 0 в качестве выходных данных… Потому что someNumber -= someArray[findTheValue], когда findTheValue == 0, определенно > 0…

2. @anon: цикл продолжается до тех пор, пока условие не станет ложным

3. Это может срабатывать каждый раз на вашем компьютере, но не является детерминированным. То, что это работает при запуске, не означает, что код хорош.

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

Ответ №1:

Доступ к элементу массива за его пределами является неопределенным поведением. То есть программе разрешено делать все, что ей заблагорассудится, отвечать 42 , потреблять ваш жесткий диск или тратить все ваши деньги. Другими словами, то, что происходит в таких случаях, полностью зависит от платформы. Это может показаться «детерминированным», но это просто потому, что вам повезло, а также, вероятно, потому, что вы только читаете из этого места, а не записываете в него.

Такой код просто плох. Не делайте этого.

Ответ №2:

В зависимости от вашего компилятора, someArray[2] является указателем на findTheValue !

Поскольку эти переменные объявляются одна за другой, вполне возможно, что они будут последовательно располагаться в памяти (я полагаю, в стеке). C на самом деле не выполняет никакого управления памятью или проверки ошибок, так что someArray[2] просто означает память в someArray[0] 2 * sizeof(int) .

Итак, когда findTheValue равно 0, мы вычитаем, затем, когда findTheValue равно 1, мы вычитаем 1. Когда findTheValue равно 2, мы вычитаем someNumber (что теперь равно 94) и завершаем работу.

Такое поведение никоим образом не гарантировано. Не полагайтесь на это!

РЕДАКТИРОВАТЬ: Вероятно, более вероятно, что someArray[2] просто указывает на мусорные (неуказанные) значения в вашей оперативной памяти. Эти значения, вероятно, больше 93 и приведут к завершению цикла.

ПРАВКА2: Или, может быть, someArray[2] и someArray[3] являются большими отрицательными числами, и вычитание обоих приводит к тому, что someNumber становится отрицательным.

Комментарии:

1. Я запускал эту программу много раз на своем компьютере и постоянно получаю один и тот же результат… Вы уверены? И это его точно такой же результат…

2. Возможно, вы правы. Я отредактировал свой пост. Попробуйте напечатать значение someArray[findTheValue] внутри цикла и расскажите нам, что вы видите?

3. Вот результат, который я постоянно вижу: — Найдите значение = 0 и someNumber = 97 и someArray [Найдите значение] = 0, найдите значение = 1 и someNumber = 96 и someArray [Найдите значение] = 1, Найдите значение = 2 и someNumber = 94 и someArray [Найдите значение] = 2 . Сумасшедшее значение равно 3

4. Как я ответил выше, первая итерация в цикле выполняет 97-0, вторая итерация выполняет 97-1, третья итерация И ДА, хотя размер массива равен 2, у него есть третья итерация, и она показывает мне 96-2, что равно 94, а затем цикл завершается и показывает crazyvalue равным 3.

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

Ответ №3:

Цикл завершается, потому что (someNumber -= someArray[findTheValue]) не установлен.

Добавив строку отладки, вы можете увидеть

 value 0 number 97 array 0
value 1 number 96 array 1
value 2 number 1208148276 array -1208148180
  

то есть выводится значение findTheValue, someNumber, someArray[Значение findTheValue]

Это не тот ответ, который я ожидал на первый взгляд.

Комментарии:

1. Извините, но я просто не получаю вывод, который вы отобразили. Я использую 64-разрядную версию ubuntu, gcc версии 4.4.5

2. Я ответил на ответ Брэда своим выводом. Как вы можете видеть, значение для someNumber -= someArray[findTheValue] всегда задано, и я могу напечатать это значение после завершения цикла for.

3. Проблема, как кто-то еще указал, заключается в том, что значение, которое будет в массиве place[2], на самом деле случайное, поэтому вы можете получить и получите разные результаты.

4. На какой ОС вы получили приведенный выше ответ и на каком компиляторе?

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

Ответ №4:

Проверка адресов:

 printf("amp;someNumber =   %pn", amp;someNumber);
printf("amp;someArray[0] = %pn", amp;someArray[0]);
printf("amp;someArray[1] = %pn", amp;someArray[1]);
printf("amp;findTheValue = %pn", amp;findTheValue);
  

выдал этот результат:

 amp;someNumber =   0xbfc78e5c
amp;someArray[0] = 0xbfc78e50
amp;someArray[1] = 0xbfc78e54
amp;findTheValue = 0xbfc78e58
  

Похоже, что по какой-то причине компилятор помещает массив в начало области стека, затем переменные, которые объявлены ниже, а затем те, которые находятся выше, в порядке их объявления. Итак, someArray[3] эффективно указывает на someNumber .

Я действительно не знаю причины, но я пробовал gcc на Ubuntu 32 bit и Visual Studio с оптимизацией и без нее, и результаты всегда были одинаковыми.