MQL4、MQL5に関する初心者からの質問、アルゴリズムやコードに関するヘルプ、ディスカッションなど。 - ページ 599

 
Nikolay Gaylis:

こんにちは。

テキスト文書の例えば7行目にカーソルを移動して、この位置から部分文字 列を抽出する方法を教えてください...。

1行で複数のテキストファイルと、1行で複数のファイルではどちらが速いですか?

1行が何バイトかを把握し、そのような値をファイルの先頭から6個までポインタを移動させる必要があります。

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

こんにちは。

1行のテキストファイルがたくさんあるのと、何行もある1つのファイルでは、どちらが速いでしょうか?

アルゴリズムの具体的な実装と解決すべき問題に依存する。おそらくあなたの場合は、最初のオプションの方が速いでしょうが、あなたのところでは性能のことは考えません。

ニコライ・ゲイリス

テキスト文書の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オブジェクトへのポインタが作成されます。ヒープはプログラムアドレス空間のメモリセグメントで、対応する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演算子がどこで、どのような状況で呼ばれるかを常に注意しなければならないので、このような構成は避けた方がよいでしょう。その代わり、クラスの 使い方を覚えればいいんです。このクラスを使うと、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が どこかにあるはずなのだ。その上、新規と削除はプログラムの異なる部分、例えば、異なるメソッドに配置することができます。

foo_analize を呼び出した後、オブジェクトがまだ必要な場合は、オブジェクトが必要とされることが保証されている他の場所に delete 演算子を配置することができます。このような普遍的な場所としては、例えば、プログラムが終了する前に呼び出されるOnDeinitが考えられる。

メインを忘れない。 new 演算子があれば、それに対する delete 演算子が必ずあるはずです。.そうしないと、メモリリークが発生します。同じオブジェクトを扱うnewと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 ..
  }

不正確です。

 
こんにちは。助けてください!400pipsになったらメッセージを送るようにインジケーターを設定しているのですが、この条件になると、メッセージが大量に送られてきます。1通だけ送信させる方法。ありがとうございました。
#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);
 }
//+------------------------------------------------------------------+