Any questions from newcomers on MQL4 and MQL5, help and discussion on algorithms and codes - page 599

 
Nikolay Gaylis:

Hello!

Can you tell me how to move the cursor to, say, line 7 in a text document, to extract a substring from this position...

Which is faster - multiple text files with one line or one file with more lines?

You need to know how many bytes are in one line and move the pointer to 6 such values from the beginning of the file.

FileSeek - Файловые операции - Справочник MQL4
FileSeek - Файловые операции - Справочник MQL4
  • docs.mql4.com
Если выставить позицию за "правую границу" файла (больше, чем размер файла), то последующая запись в файл будет будет произведена не с конца файла, а с выставленной позиции. При этом между предыдущим концом файла и выставленной позицией будут записаны неопределенные значения...
 
Nikolay Gaylis:

Hello!

Which is faster-many text files with one line or one file with many lines?

It depends on the specific implementation of the algorithm and the problem to be solved. Perhaps in your case, the first option will be faster, but I would not think about performance in your place.

Nikolay Gaylis:

Please tell me how to move cursor, say, on the 7th line in a text document, to extract substring already from this position...

Read the standard documentation. Thefile operations section. For example, you can read a file line by line with FileReadString, an example is directly from the documentation:

//--- покажем окно входных параметров при запуске скрипта 
#property script_show_inputs 
//--- параметры для чтения данных 
input string InpFileName="Trend.bin"; // имя файла 
input string InpDirectoryName="Data"; // имя директории 
//+------------------------------------------------------------------+ 
//| Script program start function                                    | 
//+------------------------------------------------------------------+ 
void OnStart() 
  { 
//--- откроем файл 
   ResetLastError(); 
   int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_BIN|FILE_ANSI);
    if(file_handle!=INVALID_HANDLE) 
     { 
      PrintFormat("Файл %s открыт для чтения",InpFileName); 
      PrintFormat("Путь к файлу: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
       //--- вспомогательные переменные 
      int    str_size; 
      string str; 
      //--- прочитаем данные из файла 
      while(!FileIsEnding(file_handle)) 
        { 
         //--- узнаем сколько символов использовано для записи времени 
         str_size=FileReadInteger(file_handle,INT_VALUE); 
         //--- прочитаем строку 
         str=FileReadString(file_handle,str_size); 
         //--- распечатаем строку 
         PrintFormat(str); 
        } 
      //--- закроем файл 
      FileClose(file_handle); 
      PrintFormat("Данные прочитаны, файл %s закрыт",InpFileName); 
     } 
   else 
      PrintFormat("Не удалось открыть файл %s, Код ошибки = %d",InpFileName,GetLastError());
   }
 

Can you tell me how to convert the value of a mouse click on a chart into a price value or vice versa?

int OnInit()
  {
   ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
   

   return(INIT_SUCCEEDED);
  }
//-------------------------------------------------------
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   int klik = CHARTEVENT_CLICK;
   Print("ID: ",id," Lparam(X): ",lparam," Dparam(Y): ",dparam," Sparam: ",sparam);
   if(id==klik)sto = true;
   si = lparam;
   Print("'",sparam,"klik ","si = ",si);
   
  }
 
 
Galim_V:

Tell me how to convert the value of a mouse click on a chart into a price value or vice versa.

Use the ChartXYToTimePrice function. See "Operations with charts" in the documentation.

 
Vasiliy Sokolov:

Use the ChartXYToTimePrice function. See "Operations with charts" in the documentation.

Thank you.

 
Vasiliy Sokolov:

So they made a mistake with CArrayObj. Instead of: CArrayObj test_objects; They wrote: CArrayObj* test_objects, but forgot to make a destructor for it; Maybe they incorrectly configured memory model to work with CArrayObj. Maybe they simply overdid it with pointers. The diagnosis is clear: using pointers where they are not needed often causes leaks.

There is a function in some class. I declare an array of CArrayObj objects in it. I add global class objects into it. When the function is over, the array of objects itself is not necessary. The objects are needed, of course.

If I create the array as a pointer CArrayObj *test_objects, I get undeleted objects in the log, which will cause an out of memory error in the end.

If I declare the array as CArrayObj test_objects, add objects to it, then it turns out that when the function ends and the objects become unavailable, because the array with objects is sort of deleted...

 
Juer:

If I declare an array as CArrayObj test_objects, add objects to it, then it turns out that when the function ends, the objects will become unavailable, because the array with objects is sort of deleted...

This is correct, because in this case, you place CArrayObj test_objects on the stack and the function's address space. When the function exits, the function address space is overwritten, including your CArrayObj test_objects.

Juer:

The function is terminated, the object array itself is not needed. The objects, of course, are needed.

Remember once and for all, if you need objects inside a CArrayObj, you also need the CArrayObj itself. CArrayObj is a mandatory packing. You can't do without it, full stop.

Juer:

If I create an array as a pointer CArrayObj *test_objects, then I get undeleted objects in the log, which will eventually lead to an out of memory error.

In this case a pointer to some CArrayObj object in the heap is created. The heap is a segment of program address space memory where memory is allocated and deleted manually with the help of the corresponding new and delete operators. It means that if you write new, there must be its mirror copy of delete somewhere. Besides, new and delete can be located in different parts of the program, for example, in different methods:

CArrayObj* foo_create()
{
  //-- Выделили память в куче, под объект CArrayObj и создали его
  CArrayObj* obj_array = new CArrayObj();
  //-- Заполняем obj_array полезной нагрузкой
  obj_array.Add(new CItem());
  ...
  ...

  //-- Выходим из функции. При этом объект CArrayObj и память под него не затирается.
  //-- Он по-прежнему доступен по указателю. Единственный указатель, который ведет
  //-- к нему это obj_array. Возвращаем его вызвавшей функции
  return obj_array;
}

void foo_analize()
{
   //-- Получили указатель obj_array из foo_create
   //-- здесь он будет под именем obj_analize
   CArrayObj* obj_analize = foo_create();
   //-- Проанализировали объекты внутри obj_analize
   ...
   ...
   ...
   //-- Здесь объект obj_analize и его элементы больше не нужены
   //-- Удаляем объект и все его элементы. Отдельно удалять элементы
   //-- не нужно. CArrayObj сделает все автоматически.
   delete obj_analize;
}

If, after calling foo_analize, objects are still needed, the delete operator can be placed somewhere else, where objects are guaranteed to be needed. Such a universal place can be OnDeinit, for example, which is called before the program is closed.

Remember the main thing, if there is a new operator, there must always be a delete operator for it. Otherwise there will be memory leaks. The new and delete operators working on the same object do not have to be "side by side" in the same method. Delete can be anywhere far away from the memory allocation, as long as delete has a reference to the allocated object in the heap.

** Although this is true, we'd better avoid such constructs because we always have to be very careful about where and under what circumstances the delete operator is called, which is not always obvious. Instead, you just have to learn how to use classes. The class allows you to automatically place and delete objects on the heap, without using new and delete operators:

class CMyCalculation
{
private:
   //-- Содержит объекты, над которыми нужно провести некоторые мат. операции
   CArrayObj m_obj_array;
   void CreateObj();
public:
   void Calc();
};
//-- Считает массив объектов CArrayObj
void CMyCalculation::Calc()
{
  //-- Если объектов нет, создаем их
  if(m_obj_array.Total() == 0)
     CreateObj();
  //-- Рассчитываем нужные нам значения на данных
  for(int i = 0; i < m_obj_array.Total(); i++)
  {
     CItem* item = m_obj_array.At(i);
     //-- обсчитывает item как нам нужно
     ...
     ...
  }
}
//-- Создает массив объектов CItem
void CMyCalculation::CreateObj()
{
   m_obj_array.Add(new CItem());
   m_obj_array.Add(new CItem());
   ...
   ...
}

This class does not contain pointers explicitly. So you don't need to use both new and delete. After exiting the program, the class will release all CItem and CArrayObj objects automatically, which makes developer's life much easier.

 
Vasiliy Sokolov:

This is correct, because in this case you place CArrayObj test_objects on the stack and the function address space. When you exit the function, the function address space is overwritten, including your CArrayObj test_objects.

Remember once and for all - if you need objects inside a CArrayObj, you need the CArrayObj itself. CArrayObj is a mandatory package. You can't do without it, full stop.

In this case, a pointer to some object CArrayObj in the heap is created. The heap is a segment of program address space memory where memory is allocated and deleted manually with the help of the corresponding new and delete operators. It means that if you write new, there must be its mirror copy of delete somewhere. Besides, new and delete can be located in different parts of the program, for example, in different methods:

If, after calling foo_analize, objects are still needed, the delete operator can be placed somewhere else, where objects are guaranteed to be needed. Such a universal place can be OnDeinit, for example, which is called before the program is closed.

Remember the main thing, if there is a new operator, there must always be a delete operator for it. Otherwise there will be memory leaks. The new and delete operators working with the same object do not have to be "side by side" in the same method. Delete can be anywhere far away from the memory allocation, as long as delete has a reference to the allocated object in the heap.

** Although this is true, we'd better avoid such constructs because we always have to be very careful about where and under what circumstances the delete operator is called, which is not always obvious. Instead, you just have to learn how to use classes. The class allows you to automatically place and delete objects on the heap, without using new and delete operators:

This class does not contain pointers explicitly. So you don't need to use both new and delete. After the program exits, the class will automatically free all CItem and CArrayObj objects, which makes life easier for the developer.

Thank you. But I haven't found an answer to my question. Where should I put delete if I declare a pointer. I repeat, the CArrayObj object is declared in a function... how can I delete it in Deinit()?

But beforehand I solved the problem like this. Before finishing the function:


CClass func()
  {
   CArrayObj test_objects;
   test_objects.Add(m_object1);
   test_objects.Add(m_object2);
   ....

   for(int i=0;i<test_objects.Total();i++)
     {
      test_objects.Detach(i);
     }
   return ..
  }
 
Juer:

Thank you. I just couldn't find an answer to my exact question. Where should I put delete if I declare a pointer. Again, the CArrayObj object is declared in a function... how can I delete it in Deinit()?

This is not a telepath club. You haven't attached your code, so you may decide for yourself where to place delete.

CClass func()
  {
   CArrayObj test_objects;
   test_objects.Add(m_object1);
   test_objects.Add(m_object2);
   ....

   for(int i=0;i<test_objects.Total();i++)
     {
      test_objects.Detach(i);
     }
   return ..
  }

Incorrect.

 
Hello. Please help, I have configured the indicator to send messages when the price reaches 400 pips, but when these conditions are reached, a bunch of messages are sent to me. How to make it send only one message. Thank you!
#property indicator_chart_window
extern int    font_size = 10;
extern color  ColorBull = DodgerBlue;
extern color  ColorBeer = Red;
extern string font_name = "rs";
//+------------------------------------------------------------------+

int start()
 {
   double k=(WindowPriceMax()-WindowPriceMin())/20;
   for(int i=WindowFirstVisibleBar(); i>=0; i--)
   {
      double rs = (NormalizeDouble(Open[i],Digits)-NormalizeDouble(Close[i],Digits))/Point;
      if (rs<0) drawtext(i, High[i]+k, DoubleToStr(rs*(-1),0), ColorBull);
      if (rs>0) drawtext(i, Low[i]-Point, DoubleToStr(rs,0), ColorBeer);
   }
   if (rs<-400) 
   {
     SendNotification ("Появился сигнал1: " + Symbol() + ", " + IntegerToString(Period()));
     Print("Сигнал отправлен!");
   }
   if (rs>400)
   {
     SendNotification("Появился сигнал2: " + Symbol() + ", " + IntegerToString(Period()));
     Print("Сигнал отправлен!");
   }
   
}
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll(0,OBJ_TEXT);
   return(0);  
}
//+------------------------------------------------------------------+
int drawtext(int n, double Y1, string l,color c)
 {
   string Name=TimeToStr(Time[n],TIME_DATE|TIME_MINUTES);
   ObjectDelete (Name);
   ObjectCreate (Name, OBJ_TEXT,0,Time[n],Y1,0,0,0,0);
   ObjectSetText(Name, l,font_size,font_name);
   ObjectSet    (Name, OBJPROP_COLOR, c);
 }
//+------------------------------------------------------------------+