Fragen von Neueinsteigern zu MQL4 und MQL5, Hilfe und Diskussion über Algorithmen und Codes - Seite 599

 
Nikolay Gaylis:

Hallo!

Können Sie mir sagen, wie ich den Cursor in einem Textdokument z. B. auf Zeile 7 bewegen kann, um eine Teilzeichenkette von dieser Position aus zu extrahieren?

Was ist schneller - mehrere Textdateien mit einer Zeile oder eine Datei mit mehreren Zeilen?

Sie müssen wissen, wie viele Bytes in einer Zeile sind, und den Zeiger auf 6 solcher Werte vom Anfang der Datei verschieben.

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

Hallo!

Was ist schneller - viele Textdateien mit einer Zeile oder eine Datei mit vielen Zeilen?

Dies hängt von der spezifischen Implementierung des Algorithmus und dem zu lösenden Problem ab. Vielleicht ist in Ihrem Fall die erste Option schneller, aber ich würde an Ihrer Stelle nicht über die Leistung nachdenken.

Nikolay Gaylis:

Bitte sagen Sie mir, wie ich den Cursor z. B. in die 7. Zeile eines Textdokuments bewegen kann, um die Teilzeichenkette bereits ab dieser Position zu extrahieren...

Lesen Sie die Standarddokumentation. Der Abschnitt über dieDateioperationen. Zum Beispiel können Sie eine Datei zeilenweise mit FileReadString lesen, ein Beispiel ist direkt aus der Dokumentation:

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

Können Sie mir sagen, wie ich den Wert eines Mausklicks in einem Diagramm in einen Preiswert umwandeln kann oder umgekehrt?

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:

Wie kann ich den Wert eines Mausklicks in einem Diagramm in einen Preiswert umwandeln oder umgekehrt?

Verwenden Sie die Funktion ChartXYToTimePrice. Siehe "Operationen mit Diagrammen" in der Dokumentation.

 
Vasiliy Sokolov:

Verwenden Sie die Funktion ChartXYToTimePrice. Siehe "Operationen mit Diagrammen" in der Dokumentation.

Ich danke Ihnen.

 
Vasiliy Sokolov:

Sie haben also einen Fehler mit CArrayObj. Statt: CArrayObj test_objects; Sie schrieben: CArrayObj* test_objects, vergaßen aber, einen Destruktor dafür zu erstellen; Vielleicht haben sie das Speichermodell für die Arbeit mit CArrayObj falsch konfiguriert. Vielleicht haben es die Programmierer mit den Zeigern einfach übertrieben. Die Diagnose ist eindeutig: Die Verwendung von Zeigern an Stellen, an denen sie nicht benötigt werden, führt häufig zu Lecks.

Es gibt eine Funktion in irgendeiner Klasse. Ich deklariere darin ein Array von CArrayObj-Objekten. Ich füge globale Klassenobjekte hinzu. Wenn die Funktion beendet ist, ist das Array der Objekte selbst nicht mehr erforderlich. Die Objekte werden natürlich benötigt.

Wenn ich das Array als Zeiger CArrayObj *test_objects erstelle, erhalte ich ungelöschte Objekte im Protokoll, was am Ende zu einem Out-of-Memory-Fehler führen wird.

Wenn ich das Array als CArrayObj test_objects deklariere und ihm Objekte hinzufüge, dann stellt sich heraus, dass, wenn die Funktion endet und die Objekte nicht mehr verfügbar sind, weil das Array mit den Objekten sozusagen gelöscht wird...

 
Juer:

Wenn ich ein Array als CArrayObj test_objects deklariere und ihm Objekte hinzufüge, dann stellt sich heraus, dass die Objekte nicht mehr verfügbar sind, wenn die Funktion endet, weil das Array mit den Objekten sozusagen gelöscht wird...

Das ist richtig, denn in diesem Fall platzieren Sie CArrayObj test_objects auf dem Stack und im Adressraum der Funktion. Wenn die Funktion beendet wird, wird der Adressraum der Funktion überschrieben, einschließlich Ihrer CArrayObj test_objects.

Juer:

Die Funktion wird beendet, das Objektarray selbst wird nicht benötigt. Die Objekte werden natürlich benötigt.

Denken Sie ein für alle Mal daran: Wenn Sie Objekte innerhalb eines CArrayObjs benötigen, brauchen Sie auch das CArrayObj selbst. CArrayObj ist eine obligatorische Verpackung. Sie können nicht darauf verzichten, ganz einfach.

Juer:

Wenn ich ein Array als Zeiger CArrayObj *test_objects, dann bekomme ich ungelöschte Objekte in das Protokoll, die schließlich zu einem out of memory Fehler führen wird.

In diesem Fall wird ein Zeiger auf ein CArrayObj-Objekt auf dem Heap erzeugt. Der Heap ist ein Segment des Programmadressraums, in dem Speicher mit Hilfe der entsprechenden new- und delete-Operatoren manuell zugewiesen und gelöscht wird. Das heißt, wenn Sie new schreiben, muss es irgendwo eine Spiegelung von delete geben. Außerdem können Neu und Löschen in verschiedenen Teilen des Programms liegen, zum Beispiel in verschiedenen Methoden:

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

Wenn nach dem Aufruf von foo_analize noch Objekte benötigt werden, kann der Löschoperator an einer anderen Stelle platziert werden, an der garantiert Objekte benötigt werden. Ein solcher universeller Ort kann z. B. OnDeinit sein, das aufgerufen wird, bevor das Programm geschlossen wird.

Denken Sie an die Hauptsache, wenn es einen neuen Operator gibt, muss es immer auch einen Löschoperator dafür geben. Andernfalls kommt es zu Speicherlecks. Die Operatoren "Neu" und "Löschen", die dasselbe Objekt bearbeiten, müssen nicht "nebeneinander" in derselben Methode stehen. Löschen kann an einem beliebigen Ort weit entfernt von der Speicherzuweisung erfolgen, solange delete einen Verweis auf das ausgewählte Objekt im Heap hat.

** Obwohl das stimmt, sollten wir solche Konstrukte besser vermeiden, denn wir müssen immer sehr vorsichtig sein, wo und unter welchen Umständen der Löschoperator aufgerufen wird, was nicht immer offensichtlich ist. Stattdessen müssen Sie nur lernen, wie man Klassen verwendet. Mit dieser Klasse können Sie automatisch Objekte auf dem Heap platzieren und löschen, ohne die Operatoren new und delete zu verwenden:

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

Diese Klasse enthält nicht explizit Zeiger. Sie brauchen also nicht sowohl neu als auch löschen zu verwenden. Nach dem Beenden des Programms gibt die Klasse automatisch alle CItem- und CArrayObj-Objekte frei, was das Leben des Entwicklers erheblich erleichtert.

 
Vasiliy Sokolov:

Das ist richtig, denn in diesem Fall legen Sie CArrayObj test_objects auf den Stack und den Funktionsadressraum. Wenn Sie die Funktion beenden, wird der Adressraum der Funktion überschrieben, einschließlich Ihrer CArrayObj test_objects.

Denken Sie ein für alle Mal daran: Wenn Sie Objekte innerhalb eines CArrayObjs benötigen, brauchen Sie das CArrayObj selbst. CArrayObj ist ein obligatorisches Paket. Sie können nicht darauf verzichten, ganz einfach.

In diesem Fall wird ein Zeiger auf ein Objekt CArrayObj auf dem Heap erstellt. Der Heap ist ein Segment des Programmadressraums, in dem Speicher mit Hilfe der entsprechenden new- und delete-Operatoren manuell zugewiesen und gelöscht wird. Das heißt, wenn Sie new schreiben, muss es irgendwo eine Spiegelung von delete geben. Außerdem können Neu und Löschen in verschiedenen Teilen des Programms liegen, zum Beispiel in verschiedenen Methoden:

Wenn nach dem Aufruf von foo_analize noch Objekte benötigt werden, kann der Löschoperator an einer anderen Stelle platziert werden, an der garantiert Objekte benötigt werden. Ein solcher universeller Ort kann z. B. OnDeinit sein, das aufgerufen wird, bevor das Programm geschlossen wird.

Denken Sie an die Hauptsache, wenn es einen neuen Operator gibt, muss es immer auch einen Löschoperator dafür geben. Andernfalls kommt es zu Speicherlecks. Die Operatoren "Neu" und "Löschen", die mit demselben Objekt arbeiten, müssen sich nicht "nebeneinander" in derselben Methode befinden. Löschen kann an einem beliebigen Ort weit entfernt von der Speicherzuweisung erfolgen, solange delete einen Verweis auf das zugewiesene Objekt im Heap hat.

** Obwohl das stimmt, sollten wir solche Konstrukte besser vermeiden, denn wir müssen immer sehr vorsichtig sein, wo und unter welchen Umständen der Löschoperator aufgerufen wird, was nicht immer offensichtlich ist. Stattdessen müssen Sie nur lernen, wie man Klassen verwendet. Mit dieser Klasse können Sie automatisch Objekte auf dem Heap platzieren und löschen, ohne die Operatoren new und delete zu verwenden:

Diese Klasse enthält nicht explizit Zeiger. Sie brauchen also nicht sowohl neu als auch löschen zu verwenden. Nach Beendigung des Programms gibt die Klasse automatisch alle CItem- und CArrayObj-Objekte frei, was dem Entwickler das Leben erleichtert.

Ich danke Ihnen. Aber ich habe keine Antwort auf meine Frage gefunden. Wo sollte ich löschen, wenn ich einen Zeiger deklariere. Ich wiederhole, das CArrayObj-Objekt wird in einer Funktion deklariert... wie kann ich es in Deinit() löschen?

Zuvor habe ich das Problem jedoch folgendermaßen gelöst. Bevor Sie die Funktion beenden:


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:

Ich danke Ihnen. Ich konnte einfach keine Antwort auf meine genaue Frage finden. Wo soll ich löschen, wenn ich einen Zeiger deklariere. Auch hier ist das CArrayObj-Objekt in einer Funktion deklariert... wie kann ich es in Deinit() löschen?

Dies ist kein Telepathenclub. Sie haben Ihren Code nicht beigefügt, so dass Sie selbst entscheiden können, wo Sie löschen möchten.

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

Falsch.

 
Hallo. Bitte helfen Sie mir, ich habe den Indikator so konfiguriert, dass er Nachrichten sendet, wenn der Preis 400 Pips erreicht, aber wenn diese Bedingungen erreicht sind, werden mir eine Reihe von Nachrichten gesendet. Wie kann man es dazu bringen, nur eine Nachricht zu senden? Ich danke Ihnen!
#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);
 }
//+------------------------------------------------------------------+
Grund der Beschwerde: