新人对MQL4和MQL5的任何问题,对算法和代码的帮助和讨论 - 页 599

 
Nikolay Gaylis:

你好!

你能告诉我如何将光标移动到,比如说,文本文档中的第7行,从这个位置提取一个子串 吗?

一个行的多个文本文件和一个行的多个文件哪个更快?

你需要知道一行有多少个字节,并将指针从文件的开头移到6个这样的值。

FileSeek - Файловые операции - Справочник MQL4
FileSeek - Файловые операции - Справочник MQL4
  • docs.mql4.com
Если выставить позицию за "правую границу" файла (больше, чем размер файла), то последующая запись в файл будет будет произведена не с конца файла, а с выставленной позиции. При этом между предыдущим концом файла и выставленной позицией будут записаны неопределенные значения...
 
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,我在日志中会得到未删除的对象,这将导致最后出现内存不足的错误。

如果我把数组声明为CArrayObj test_objects,向其添加对象,那么结果是,当函数结束时,对象变得不可用,因为带有对象的数组被某种程度上删除了......

 
Juer:

如果我把一个数组声明为CArrayObj test_objects,向其中添加对象,那么结果是,当函数完成后,对象变得不可用,因为带有对象的数组被某种程度上删除了...

这是正确的,因为在这种情况下,你把CArrayObj test_objects放在堆栈和函数的地址空间上。当函数退出时,函数的地址空间被覆盖,包括你的CArrayObj test_objects。

朱尔

该函数被终止,对象阵列本身不需要。当然,这些对象是需要的。

请永远记住,如果你需要CArrayObj里面的对象,你也需要CArrayObj本身。CArrayObj是一个强制性的包装。你不能没有它,句号。

朱尔

如果我以指针形式创建一个数组CArrayObj *test_objects,那么我在日志中得到未删除的对象,这最终会导致内存不足的错误。

在这种情况下,会创建一个指向堆中某个CArrayObj对象的指针。堆是程序地址空间内存的一个部分,内存是在相应的新建 和删除操作符的帮助 下手动分配和删除的。这意味着,如果你写了新的东西,在某个地方一定有它的镜像拷贝的删除。此外,新建和删除可以位于程序的不同部分,例如,不同的方法。

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之后,仍然需要对象,那么可以将删除操作符放在其他地方,在那里可以保证需要对象。这样一个通用的地方可以是OnDeinit,例如,它在程序关闭之前被调用。

记住主要的事情。 如果有一个新的操作者,就一定有一个删除操作者。.否则就会出现内存泄露的情况。在同一个对象上工作的新建和删除操作者不一定要在同一个方法中 "并排"。删除可以在远离内存分配的任何地方,只要删除在堆中有一个对所选对象的引用。

** 虽然这是真的,但我们最好避免这样的结构,因为我们总是要非常小心在什么地方和什么情况下调用删除操作符,这并不总是很明显。相反,你只需要学习如何使用。该类允许你自动在堆上放置和删除对象,而无需使用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());
   ...
   ...
}

该类不明确地包含指针。所以你不需要同时使用新建和删除。在退出程序后,该类会自动释放所有的Item和CArrayObj对象,这让开发者的生活变得更加轻松。

 
Vasiliy Sokolov:

这是正确的,因为在这种情况下,你把CArrayObj test_objects放在堆栈上,和函数地址空间。当你退出函数时,函数的地址空间被覆盖,包括你的CArrayObj test_objects。

一劳永逸地记住--如果你需要CArrayObj里面的对象,你需要CArrayObj本身。CArrayObj是一个强制性包。你不能没有它,句号。

在这种情况下,一个指向堆中某个对象CArrayObj的指针被创建。堆是程序地址空间内存的一个部分,内存是在相应的新建 和删除操作符 的帮助下手动分配和删除的。这意味着,如果你写了新的东西,在某个地方一定有它的镜像拷贝的删除。此外,新建和删除可以位于程序的不同部分,例如,不同的方法。

如果在调用foo_analize之后,仍然需要对象,那么可以将删除操作符放在其他地方,在那里可以保证需要对象。这样一个通用的地方可以是OnDeinit,例如,它在程序关闭之前被调用。

记住主要的事情。 如果有一个新的操作者,就一定有一个删除操作者。.否则就会出现内存泄露的情况。对同一个对象进行操作的新建和删除操作者不一定要在同一个方法中 "并排"。删除可以在远离内存分配的任何地方,只要删除在堆中有一个对被分配对象的引用。

** 虽然这是真的,但我们最好避免这样的结构,因为我们总是要非常小心在什么地方和什么情况下调用删除操作符,这并不总是很明显。相反,你只需要学习如何使用。该类允许你自动在堆上放置和删除对象,而无需使用new和delete操作符。

该类不明确地包含指针。所以你不需要同时使用新建和删除。在程序退出后,该类会自动释放所有的Item和CArrayObj对象,这让开发者的生活更轻松。

谢谢你。但我还没有找到问题的答案。如果我声明一个指针,我应该把删除放在哪里。我再说一遍,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:

谢谢你。我只是找不到我的确切问题的答案。如果我声明一个指针,我应该把删除放在哪里。同样,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 ..
  }

不正确。

 
你好。请帮助,我已经将指标配置为当价格达到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);
 }
//+------------------------------------------------------------------+
原因: