Toute question des nouveaux arrivants sur MQL4 et MQL5, aide et discussion sur les algorithmes et les codes. - page 599

 
Nikolay Gaylis:

Bonjour !

Pouvez-vous me dire comment déplacer le curseur à, disons, la ligne 7 dans un document texte, pour extraire une sous-chaîne de cette position...

Qu'est-ce qui est le plus rapide - plusieurs fichiers texte avec une ligne ou un fichier avec plusieurs lignes ?

Vous devez savoir combien d'octets se trouvent sur une ligne et déplacer le pointeur sur 6 de ces valeurs à partir du début du fichier.

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

Bonjour !

Qu'est-ce qui est le plus rapide : plusieurs fichiers texte avec une seule ligne ou un seul fichier avec plusieurs lignes ?

Cela dépend de l'implémentation spécifique de l'algorithme et du problème à résoudre. Peut-être que dans votre cas, la première option sera plus rapide, mais je ne penserais pas aux performances à votre place.

Nikolay Gaylis:

Veuillez me dire comment déplacer le curseur, disons, sur la 7ème ligne d'un document texte, pour extraire la sous-chaîne déjà à partir de cette position...

Lisez la documentation standard. La section desopérations sur les fichiers. Par exemple, vous pouvez lire un fichier ligne par ligne avec FileReadString, un exemple tiré directement de la 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());
   }
 

Pouvez-vous me dire comment convertir la valeur d'un clic de souris sur un graphique en une valeur de prix ou 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:

Dites-moi comment convertir la valeur d'un clic de souris sur un graphique en une valeur de prix ou vice versa.

Utilisez la fonction ChartXYToTimePrice. Voir "Opérations avec des graphiques" dans la documentation.

 
Vasiliy Sokolov:

Utilisez la fonction ChartXYToTimePrice. Voir "Opérations avec des graphiques" dans la documentation.

Merci.

 
Vasiliy Sokolov:

Ils ont donc fait une erreur avec CArrayObj. Au lieu de : CArrayObj test_objects ; Ils ont écrit : CArrayObj* test_objects, mais ont oublié de créer un destructeur pour celui-ci; Peut-être ont-ils mal configuré le modèle de mémoire pour fonctionner avec CArrayObj. Peut-être que les programmeurs ont simplement exagéré avec les pointeurs. Le diagnostic est clair : l'utilisation de pointeurs là où ils ne sont pas nécessaires provoque souvent des fuites.

Il y a une fonction dans une certaine classe. Je déclare un tableau d'objets CArrayObj dans celui-ci. J'y ajoute des objets de classe globale. Lorsque la fonction est terminée, le tableau d'objets lui-même n'est pas nécessaire. Les objets sont nécessaires, bien sûr.

Si je crée le tableau en tant que pointeur CArrayObj *test_objects, j'obtiendrai des objets non supprimés dans le journal, ce qui provoquera une erreur de mémoire à la fin.

Si je déclare le tableau comme CArrayObj test_objects, que j'y ajoute des objets, il s'avère que lorsque la fonction se termine et que les objets deviennent indisponibles, car le tableau avec les objets est en quelque sorte supprimé...

 
Juer:

Si je déclare un tableau comme CArrayObj test_objects, que j'y ajoute des objets, il s'avère que lorsque la fonction se termine et que les objets deviennent indisponibles, car le tableau avec les objets est en quelque sorte supprimé...

C'est correct, car dans ce cas, vous placez CArrayObj test_objects sur la pile et dans l'espace d'adressage de la fonction. Lorsque la fonction se termine, l'espace d'adressage de la fonction est écrasé, y compris vos CArrayObj test_objects.

Juer:

La fonction est terminée, le tableau d'objets lui-même n'est pas nécessaire. Les objets, bien sûr, sont nécessaires.

Rappelez-vous une fois pour toutes que si vous avez besoin d'objets à l'intérieur d'un CArrayObj, vous avez également besoin du CArrayObj lui-même. CArrayObj est un emballage obligatoire. Vous ne pouvez pas vous en passer, point final.

Juer:

Si je crée un tableau sous la forme d'un pointeur CArrayObj *test_objects, j'obtiens des objets non supprimés dans le journal, ce qui conduit éventuellement à une erreur de mémoire insuffisante.

Dans ce cas, un pointeur vers un objet CArrayObj dans le tas est créé. Le tas est un segment de la mémoire de l'espace d'adressage du programme où la mémoire est allouée et supprimée manuellement à l'aide des opérateurs new et delete correspondants. Cela signifie que si vous écrivez new, il doit y avoir sa copie miroir de delete quelque part. En outre, le nouveau et l'effacement peuvent se trouver dans des parties différentes du programme, par exemple, dans des méthodes différentes :

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

Si, après l'appel de foo_analize, des objets sont encore nécessaires, l'opérateur de suppression peut être placé à un autre endroit, où les objets sont garantis d'être nécessaires. Un tel lieu universel peut être OnDeinit, par exemple, qui est appelé avant la fermeture du programme.

N'oubliez pas l'essentiel, s'il existe un nouvel opérateur, il doit toujours y avoir un opérateur de suppression pour celui-ci. Sinon, il y aura des fuites de mémoire. Les opérateurs de création et de suppression travaillant sur le même objet ne doivent pas nécessairement être "côte à côte" dans la même méthode. Delete peut se trouver n'importe où loin de l'allocation de mémoire, tant que delete a une référence à l'objet alloué dans le tas.

** Bien que cela soit vrai, nous ferions mieux d'éviter de telles constructions car nous devons toujours faire très attention à l'endroit et aux circonstances où l'opérateur delete est appelé, ce qui n'est pas toujours évident. Au lieu de cela, il suffit d'apprendre à utiliser les classes. Cette classe vous permet de placer et de supprimer automatiquement des objets sur le tas, sans utiliser les opérateurs new et 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());
   ...
   ...
}

Cette classe ne contient pas explicitement de pointeurs. Vous n'avez donc pas besoin d'utiliser à la fois new et delete. Après avoir quitté le programme, la classe libère automatiquement tous les objets CItem et CArrayObj, ce qui facilite grandement la vie du développeur.

 
Vasiliy Sokolov:

C'est correct, car dans ce cas, vous placez CArrayObj test_objects sur la pile, et l'espace d'adresse de la fonction. Lorsque vous quittez la fonction, l'espace d'adressage de la fonction est écrasé, y compris vos CArrayObj test_objects.

Rappelez-vous une fois pour toutes que si vous avez besoin d'objets à l'intérieur d'un CArrayObj, vous avez besoin du CArrayObj lui-même. CArrayObj est un paquetage obligatoire. Vous ne pouvez pas vous en passer, point final.

Dans ce cas, un pointeur vers un objet CArrayObj dans le tas est créé. Le tas est un segment de la mémoire de l'espace d'adressage du programme où la mémoire est allouée et supprimée manuellement à l'aide des opérateurs new et delete correspondants. Cela signifie que si vous écrivez new, il doit y avoir sa copie miroir de delete quelque part. En outre, le nouveau et l'effacement peuvent se trouver dans des parties différentes du programme, par exemple, dans des méthodes différentes :

Si, après l'appel de foo_analize, des objets sont encore nécessaires, l'opérateur de suppression peut être placé à un autre endroit, où les objets sont garantis d'être nécessaires. Un tel lieu universel peut être OnDeinit, par exemple, qui est appelé avant la fermeture du programme.

N'oubliez pas l'essentiel, s'il existe un nouvel opérateur, il doit toujours y avoir un opérateur de suppression pour celui-ci. Sinon, il y aura des fuites de mémoire. Les opérateurs de création et de suppression travaillant avec le même objet ne doivent pas nécessairement être "côte à côte" dans la même méthode. La suppression peut se faire n'importe où, loin de l'allocation de mémoire, tant que la suppression a une référence à l'objet alloué dans le tas.

** Bien que cela soit vrai, nous ferions mieux d'éviter de telles constructions car nous devons toujours faire très attention à l'endroit et aux circonstances où l'opérateur delete est appelé, ce qui n'est pas toujours évident. Au lieu de cela, il suffit d'apprendre à utiliser les classes. Cette classe vous permet de placer et de supprimer automatiquement des objets sur le tas, sans utiliser les opérateurs new et delete :

Cette classe ne contient pas explicitement de pointeurs. Vous n'avez donc pas besoin d'utiliser à la fois new et delete. Après la sortie du programme, la classe libère automatiquement tous les objets CItem et CArrayObj, ce qui facilite la vie du développeur.

Merci. Mais je n'ai pas trouvé de réponse à ma question. Où dois-je mettre delete si je déclare un pointeur. Je répète, l'objet CArrayObj est déclaré dans une fonction... comment puis-je le supprimer dans Deinit() ?

Mais auparavant, j'ai résolu le problème de la façon suivante. Avant de terminer la fonction :


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:

Merci. Je n'ai pas trouvé de réponse à ma question exacte. Où dois-je mettre delete si je déclare un pointeur. Encore une fois, l'objet CArrayObj est déclaré dans une fonction... comment puis-je le supprimer dans Deinit() ?

Ce n'est pas un club de télépathes. Vous n'avez pas joint votre code, vous pouvez donc décider vous-même où placer la suppression.

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

C'est faux.

 
Bonjour. Aidez-moi, j'ai configuré l'indicateur pour envoyer des messages lorsque le prix atteint 400 pips, mais lorsque ces conditions sont atteintes, un tas de messages me sont envoyés. Comment faire pour qu'il n'envoie qu'un seul message. Merci !
#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);
 }
//+------------------------------------------------------------------+
Raison: