Нужна помощь по массивам "array out of range"

 

Есть индикатор объёмов mql4


При работе бывает что выходит за пределы массива

В тестере сразу ошибка 

Не могу решить эту проблему

Файлы:
 

Когда вы писали этот код - вы ж должны были убедиться, что значение index2 указывает на существующий элемент массива TPOperPrice[] !

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

Я бы на вашем месте всегда проверял получившиеся индексы, а потом - прошелся бы в отладчике, чтобы понять, как они формируются.

 
George Merts:

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


Ну да точно.

В таком виде теперь всё отлично работает: 

if (TPOperPrice[index2] <= 0) TPOperPrice[index2] = 1;
 
Natalya Dzerzhinskaya:

Ну да точно.

В таком виде теперь всё отлично работает: 


Все равно не сделана проверка. Вы ведь проверили значение элемента массива. А речь идет о том, чтобы не обратиться к несуществующему элементу массива. Проверяйте индекс элемента. Только потом можно обращаться к значению массива по этому индексу. Идеальный вариант проверки такой:

if (nArrayIndex >= 0 && nArrayIndex < ArraySize(array))
{
   // индекс nArraySize элемента массива array корректный. Можно обращаться к значению элемента массива
}
 
Ihor Herasko:

Все равно не сделана проверка. Вы ведь проверили значение элемента массива. А речь идет о том, чтобы не обратиться к несуществующему элементу массива. Проверяйте индекс элемента. Только потом можно обращаться к значению массива по этому индексу. Идеальный вариант проверки такой:


Не понятно.
Вот у меня есть индекс 2 на который жалуется

        index = (int)MathRound(abovePrice / onetick);
        int index2 = (int)MathRound(belowPrice / onetick);

        if  (TPOperPrice[index2] <= 0) TPOperPrice[index2] = 1; //ЭТО НОВОЕ УСЛОВИЕ
        if (((TPOperPrice[index] >= TPOperPrice[index2]) || (belowPrice < SessionMin)) && (abovePrice <= SessionMax))
                        {
                        TPOcount += TPOperPrice[index];
                        up_offset++;
                        }
                        else
                        {
                        TPOcount += TPOperPrice[index2];
                        down_offset++;
                        }
 
Natalya Dzerzhinskaya:

Не понятно.
Вот у меня есть индекс 2 на который жалуется

А какой такой сакральный смысл в таком вычислении с округлением индекса массива?

 
Natalya Dzerzhinskaya:

Не понятно.
Вот у меня есть индекс 2 на который жалуется


Вот содержимое переменной index2 и нужно проверить. Это индекс элемента массива, к которому происходит далее обращение. А Вы проверяете содержимое элемента массива. Такого элемента может и не быть.

 
Alexey Viktorov:

А какой такой сакральный смысл в таком вычислении с округлением индекса массива?


Каждый элемент массива соответствует своей цене. Например, интервал цен от 1.18 до 1.19 - это 1000 элементов массива. Индекс 0 - цена 1.18, а индекс 999 - цена 1.18999. Теперь нужно записать информацию для цены 1.18545. Как найти индекс? Так и находим: 1.18545 - 1.18 = 0.0545. Далее делим на величину пункта и округляем до целого, т. к. имеем дело с вещественными числами.

 
Ihor Herasko:

Вот содержимое переменной index2 и нужно проверить. Это индекс элемента массива, к которому происходит далее обращение. А Вы проверяете содержимое элемента массива. Такого элемента может и не быть.


У меня с массивами вообще туго.
Всё виснет если такая проверка:

if(((index2 >= 0 && index2 < ArraySize(TPOperPrice) && TPOperPrice[index] >= TPOperPrice[index2]) || (belowPrice < SessionMin)) && (abovePrice <= SessionMax))
{
TPOcount += TPOperPrice[index];
up_offset++;
}
else
{
if(index2 >= 0 && index2 < ArraySize(TPOperPrice)) TPOcount += TPOperPrice[index2];
down_offset++;
}
 
Natalya Dzerzhinskaya:

У меня с массивами вообще туго.

Простой пример. Есть килограмм конфет (содержимое массива), но разных видов. Каждый из видов конфет нужно поместить в свою коробку (элемент массива). Примерно посмотрев, какие конфеты есть, решаем, что потребуется пять коробок (требуется массив из 5-и элементов). На каком-то этапе сортировки оказывается, что есть мы не учли еще и шестой вид конфет. Но коробки  (нужен массив из 6-и элементов) для него у нас нет. В обычной жизни мы озаботимся поиском шестой коробки (расширение массива). А в приведенном не делается расширение массива. Попросту пишутся данные туда, где должен быть дополнительный элемент массива. То есть шестой вид конфет складывается в несуществующую коробку.


Всё виснет если такая проверка:

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

По большому счету, нужно заново продумать всю логику индикатора. По-моему, проблема в том, что изначально неправильно рассчитан размер массива TPOpenPrice. Ну а если глубоко не вникать в логику построения индикатора, то можно сделать такую "припарку":

                while (TPOcount < ValueControlTPO)
                {
                        double abovePrice = PriceOfMaxRange + up_offset * onetick;
                        double belowPrice = PriceOfMaxRange - down_offset * onetick;
                        // If belowPrice is out of the session's range then we should add only abovePrice's TPO's, and vice versa.
                        int nArrayLastElement = ArraySize(TPOperPrice) - 1;
                        index = (int)MathMax(MathMin(nArrayLastElement, MathRound(abovePrice / onetick)), 0);
                        int index2 = (int)MathMax(MathMin(nArrayLastElement, MathRound(belowPrice / onetick)), 0);
                        if (((TPOperPrice[index] >= TPOperPrice[index2]) || (belowPrice < SessionMin)) && (abovePrice <= SessionMax))
                        {
                                TPOcount += TPOperPrice[index];
                                up_offset++;
                        }
                        else
                        {
                                TPOcount += TPOperPrice[index2];
                                down_offset++;
                        }
                }
 
Ihor Herasko:

По большому счету, нужно заново продумать всю логику индикатора. По-моему, проблема в том, что изначально неправильно рассчитан размер массива TPOpenPrice. Ну а если глубоко не вникать в логику построения индикатора, то можно сделать такую "припарку":

Этот пример тоже виснет.

Если по умолчанию код и выше по коду поправить инициализируемое значение с 0 на 1, то всё работает чисто.



index = (int)MathRound(abovePrice / onetick);
int index2 = (int)MathRound(belowPrice / onetick);
if (((TPOperPrice[index] >= TPOperPrice[index2]) || (belowPrice < SessionMin)) && (abovePrice <= SessionMax))
{
TPOcount += TPOperPrice[index];
up_offset++;
}
else
{
TPOcount += TPOperPrice[index2];
down_offset++;
}
Причина обращения: