Тайна касательно цикла - PullRequest
2 голосов
/ 01 февраля 2011

Я застрял с этой загадкой относительно цикла.

    int abc[3], i, j;
    for(j=0; j<3; j++);
    printf("%d\n", j);
    abc[j] = abc[j] + 3;
    printf("%d \n", j);


Output: 

3
6 

Вывод должен быть 3,3, так как я не изменил значение j.

Добавление 3 к j-му значению abc привело к изменению значения j на 3. Это происходит только при выходе из цикла for и последующей попытке изменить значение abc [j].

Может быть, я упускаю что-то довольно очевидное. Любая помощь будет высоко ценится.

Ответы [ 4 ]

15 голосов
/ 01 февраля 2011

У вас переполнение буфера, так как вы объявили, что ваш массив имеет размер 3 int abc[3];, но вы индексируете 4-й элемент;Это Неопределенное поведение .

abc[j] = abc[j] + 3; // j = 3 here, overflow

Скорее всего, вы видите, что j находится в стеке сразу за вашим массивом abc и поэтому, когда вы переполняете одно прошлоемассив с abc[3], вы фактически модифицируете память, которая содержит j.

* Обратите внимание, что нигде в стандарте C не упоминается слово stack , этодетали реализации и могут меняться от системы к системе.Отчасти это является причиной того, что это Неопределенное поведение , и вы получаете ответы от людей, что они видят два 3 в качестве вывода.

5 голосов
/ 01 февраля 2011

Вы индексируете после конца массива ( переполнение буфера ) и переназначаете другие переменные в стеке.

int abc[3], i, j;
// Your stack looks like this (single 'x' is one byte):
// |abc[0]|abc[1]| abc[2]| j  |  i |
// 
// |xxxx  |xxxx  |xxxx   |xxxx|xxxx|
// 
for(j=0; j<3; j++);
printf("%d\n", j);
// j = 3 at this point
// abc[3] points past the end of the array abc, in this case, at j.
// So the next statement increments j by 3.
abc[j] = abc[j] + 3;
printf("%d \n", j);

Чтобы проверить, попробуйте добавить следующие операторы вend:

printf("%d\n", &i == &abc[3]);
printf("%d\n", &j == &abc[3]);

EDIT

Точная структура стека будет зависеть от используемого вами компилятора:

misha@misha-desktop:~/Desktop/stackoverflow$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
misha@misha-desktop:~/Desktop/stackoverflow$ ./a.out
3
3

Вот почему он отлично работает на моей машине - оператор:

printf("abc: %x abc[3]: %x i: %x j: %x\n", &abc, &abc[3], &i, &j);

дает следующий вывод:

abc: 4cd0aa70 abc[3]: 4cd0aa7c i: 4cd0aa8c j: 4cd0aa88

Таким образом, стек на самом деле:

//  aa70   aa74     aa78   aa7c            aa88  aa8c
// |abc[0]|abc[1]| abc[2]|      |  ....  |  j  |  i  |

Таким образом, когда он получает доступ к abc[3], он получает доступ к 0x4cd0aa7c, который является просто "мертвым пространством".

1 голос
/ 01 февраля 2011

Когда J = 3, abc [j] относится к 4-му элементу, поскольку индексы массива начинаются с 0, а не с 1. Итак, вы пытаетесь получить доступ к расположению, которое находится за пределами области памяти массива abc. По случайному совпадению это местоположение совпадает с местоположением J. Следовательно, значение J изменяется. Попробуйте изменить порядок объявления переменных, чтобы лучше понять это поведение.

Спасибо,
Vamyip

0 голосов
/ 01 февраля 2011

для (j = 0; j <3; j ++); </p>

У вас есть точка с запятой в конце цикла for. Проблема решена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...