Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам - страница 599

 
Nikolay Gaylis:

Здравствуйте!

Подскажите пожалуйста как перенести курсор ,скажем на 7 строчку в текстовом документе,для извлечения подстроки уже с этой позиции...

Что будет быстрее-много текстовых файлов с одной строкой или один файл с большим количеством строк?

Нужно знать сколько байт в одной строке и переместить указатель на 6 таких значений от начала файла.

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

Здравствуйте!

Что будет быстрее-много текстовых файлов с одной строкой или один файл с большим количеством строк?

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

Nikolay Gaylis:

Подскажите пожалуйста как перенести курсор ,скажем на 7 строчку в текстовом документе,для извлечения подстроки уже с этой позиции...

Читайте стандартную документацию. Раздел "Файловые операции". Например можно построчно считать файл с помощью FileReadString, пример прямо из документации:

//--- покажем окно входных параметров при запуске скрипта 
#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());
   }
 

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

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:

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

Используйте функцию ChartXYToTimePrice. См. раздел "Операции с графиками" в документации.

 
Vasiliy Sokolov:

Используйте функцию ChartXYToTimePrice. См. раздел "Операции с графиками" в документации.

 Благодарю.

 
Vasiliy Sokolov:

Значит накосячили с CArrayObj. Вместо: CArrayObj test_objects; Написали: CArrayObj* test_objects, а диструктор для него забыли сделать; Возможно неправильно сконфигурировали модель памяти по работе с CArrayObj. Может просто с указателями перемудрили. Диагноз однозначный: использование указателей там, где они не нужны, часто приводит к утечкам. 

Есть функция в каком-то классе. В ней я объявляю массив объектов CArrayObj. В него добавляю глобальные объекты класса. Закончилась функция, сам массив объектов не нужен. Объекты, разумеется, нужны.

Если я создаю массив как указатель CArrayObj *test_objects, то потом получаю undeleted objects в логе, что приведет в конце концов к ошибке out of memory. 

Если я объявляю массив так CArrayObj test_objects, добавляю в него объекты, то получается по окончании действия функции и объекты станут недоступны, т.к. массив с объектами как бы удалился...

 
Juer:

Если я объявляю массив так CArrayObj test_objects, добавляю в него объекты, то получается по окончании действия функции и объекты станут недоступны, т.к. массив с объектами как бы удалился...

Все правильно, потому что в этом случае вы размещаете CArrayObj test_objects на стеке, а адресном пространстве функции. Когда происходит выход из функции, адресное пространство функции затирается, включая и Ваш  CArrayObj test_objects.

Juer:

Закончилась функция, сам массив объектов не нужен. Объекты, разумеется, нужны.

Запомните раз и навсегда - если нужны объекты внутри CArrayObj, то и сам CArrayObj нужен. CArrayObj обязательная упаковка. Без него никак, точка.

Juer:

Если я создаю массив как указатель CArrayObj *test_objects, то потом получаю undeleted objects в логе, что приведет в конце концов к ошибке out of memory. 

В этом случае создается указатель на некий объект CArrayObj в куче. Куча - это сегмент памяти адресного пространства программы, выделение и удаление памяти в которой происходит вручную, с помощью соответствующих операторов new и delete. Это значит что если Вы пишите new, то обязательно где-то должен быть зеркальный близнец delete. При том new и delete могут располагаться в разных частях программы, например в разных методах:

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

Если и после вызова foo_analize объекты по-прежнему нужны, то оператор delete можно перенести в другое место, при достижении которого объекты гарантированно становятся ну нужными. Таким универсальным местом может быть OnDeinit например, который вызывается перед закрытием программы.

Запомните главное, если есть оператор new, всегда должен быть оператор delete для него. В противном случае будут утечки памяти. Операторы new и delete работающие с одним и тем же объектом не обязательно должны располагаться в одном методе "рядом". Delete может быть где угодно далеко от места выделения памяти, главное, что бы у delete была ссылка на выделенный объект в куче.

** Замечу что сказанное хотя и является верным, лучше избегать подобных конструкций, т.к. всегда приходится очень внимательно смотреть где и при каких обстоятельствах вызывать оператор delete, что не всегда является очевидным. Вместо этого нужно просто научиться использовать классы. Класс позволяет автоматически размешать и удалять объекты на куче, без использования операторов new и delete:

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());
   ...
   ...
}

Данный класс не содержит указателей в явном виде. Значит не нужно использовать как new так и delete. После выхода из программы, класс освободит все объекты CItem и CArrayObj автоматически, что здорово упрощает жизнь разработчику.

 
Vasiliy Sokolov:

Все правильно, потому что в этом случае вы размещаете CArrayObj test_objects на стеке, а адресном пространстве функции. Когда происходит выход из функции, адресное пространство функции затирается, включая и Ваш  CArrayObj test_objects.

Запомните раз и навсегда - если нужны объекты внутри CArrayObj, то и сам CArrayObj нужен. CArrayObj обязательная упаковка. Без него никак, точка.

В этом случае создается указатель на некий объект CArrayObj в куче. Куча - это сегмент памяти адресного пространства программы, выделение и удаление памяти в которой происходит вручную, с помощью соответствующих операторов new и delete. Это значит что если Вы пишите new, то обязательно где-то должен быть зеркальный близнец delete. При том new и delete могут располагаться в разных частях программы, например в разных методах:

Если и после вызова foo_analize объекты по-прежнему нужны, то оператор delete можно перенести в другое место, при достижении которого объекты гарантированно становятся ну нужными. Таким универсальным местом может быть OnDeinit например, который вызывается перед закрытием программы.

Запомните главное, если есть оператор new, всегда должен быть оператор delete для него. В противном случае будут утечки памяти. Операторы new и delete работающие с одним и тем же объектом не обязательно должны располагаться в одном методе "рядом". Delete может быть где угодно далеко от места выделения памяти, главное, что бы у delete была ссылка на выделенный объект в куче.

** Замечу что сказанное хотя и является верным, лучше избегать подобных конструкций, т.к. всегда приходится очень внимательно смотреть где и при каких обстоятельствах вызывать оператор delete, что не всегда является очевидным. Вместо этого нужно просто научиться использовать классы. Класс позволяет автоматически размешать и удалять объекты на куче, без использования операторов new и delete:

Данный класс не содержит указателей в явном виде. Значит не нужно использовать как new так и delete. После выхода из программы, класс освободит все объекты CItem и CArrayObj автоматически, что здорово упрощает жизнь разработчику.

Спасибо. Только что-то на мой конкретно вопрос я не нашёл ответа. Куда мне delete поместить, если я объявляю указатель. Повторяю объект CArrayObj объявляется в функции... как я могу его удалять в Deinit()?

Но предварительно я решил проблему вот так. Перед завершением функции:


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:

Спасибо. Только что-то на мой конкретно вопрос я не нашёл ответа. Куда мне delete поместить, если я объявляю указатель. Повторяю объект CArrayObj объявляется в функции... как я могу его удалять в Deinit()?

Здесь не клуб телепатов. Свой код Вы не приложили, поэтому о том, где размещать 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 ..
  }

Неправильно. 

 
Здравствуйте. Помогите, пожалуйста, я настроил индикатор чтобы он отправлял сообщения по достижению цены 400 пунктов, но по достижению этих условий мне отправляется куча сообщений. Как сделать так, чтобы отправлялось только одно. Спасибо!   
#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);
 }
//+------------------------------------------------------------------+
Причина обращения: