Как заканчивается этот цикл и являются ли результаты детерминированными? - PullRequest
3 голосов
/ 16 апреля 2011

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

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

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;
}

Ответы [ 4 ]

2 голосов
/ 16 апреля 2011

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

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

1 голос
/ 16 апреля 2011

Цикл завершается, потому что (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 голос
/ 16 апреля 2011

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

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

Так что, когда findTheValue равно 0, мы вычитаем, тогда когда findTheValue равно 1,мы вычитаем 1. Когда findTheValue равно 2, мы вычитаем someNumber (который теперь равен 94) и выходим.

Это поведение ни в коем случае не гарантируется .Не надейтесь на это!

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

EDIT2: Или, возможно, someArray[2] и someArray[3] - большие отрицательные числа, и вычитание обоих приводит к тому, что someNumber переходит на отрицательное значение.

0 голосов
/ 16 апреля 2011

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

printf("&someNumber =   %p\n", &someNumber);
printf("&someArray[0] = %p\n", &someArray[0]);
printf("&someArray[1] = %p\n", &someArray[1]);
printf("&findTheValue = %p\n", &findTheValue);

дал такой вывод:

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

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

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

...