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 개체에 대한 포인터가 생성됩니다. 힙은 해당 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를 호출한 후에도 객체가 여전히 필요한 경우 삭제 연산자를 다른 위치로 이동할 수 있으며 도달하면 객체가 필요하게 됩니다. 이러한 일반적인 장소는 예를 들어 프로그램이 종료되기 전에 호출되는 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());
   ...
   ...
}

이 클래스는 명시적으로 포인터를 포함하지 않습니다. 따라서 new와 delete를 모두 사용할 필요가 없습니다. 프로그램을 종료한 후 클래스는 모든 CItem 및 CArrayObj 개체를 자동으로 해제하여 개발자의 삶을 크게 단순화합니다.

 
Vasiliy Sokolov :

맞습니다. 이 경우 함수의 주소 공간이 아니라 스택에 CArrayObj test_objects를 할당하기 때문입니다. 함수가 종료되면 CArrayObj test_objects를 포함하여 함수의 주소 공간을 덮어씁니다.

한 번만 기억하십시오. CArrayObj 내부에 개체가 필요한 경우 CArrayObj 자체가 필요합니다. CArrayObj는 래핑이 필요합니다. 그가 없이는 아무것도 아니다.

이 경우 힙의 일부 CArrayObj 개체에 대한 포인터가 생성됩니다. 힙은 해당 new 및 delete 연산자 를 사용하여 메모리가 수동으로 할당 및 삭제되는 프로그램 주소 공간의 메모리 세그먼트입니다. 이것은 새로 작성하는 경우 어딘가에 삭제 의 미러 쌍이 있어야 함을 의미합니다. 또한 new 및 delete는 프로그램의 다른 부분, 예를 들어 다른 방법에서 찾을 수 있습니다.

foo_analize를 호출한 후에도 객체가 여전히 필요한 경우 삭제 연산자를 다른 위치로 이동할 수 있으며 도달하면 객체가 필요하게 됩니다. 이러한 일반적인 장소는 예를 들어 프로그램이 종료되기 전에 호출되는 OnDeinit일 수 있습니다.

새로운 연산자가 있으면 항상 삭제 연산자가 있어야 한다는 점을 기억하세요. 그렇지 않으면 메모리 누수가 발생합니다. 동일한 개체에서 작동하는 새 연산자와 삭제 연산자는 "근처" 같은 메서드에 있을 필요가 없습니다. 삭제는 힙에 할당된 개체에 대한 참조가 있는 한 메모리가 할당된 곳에서 멀리 떨어져 있을 수 있습니다.

** 위의 내용은 사실이지만 그러한 구성은 피하는 것이 좋습니다. 항상 명확하지 않은 삭제 연산자를 호출할 위치와 상황을 매우 주의 깊게 살펴봐야 합니다. 대신, 당신은 단지 사용법을 배우기만 하면 됩니다. 이 클래스를 사용하면 new 및 delete 연산자를 사용하지 않고 힙에서 객체를 자동으로 할당하고 삭제할 수 있습니다.

이 클래스는 명시적으로 포인터를 포함하지 않습니다. 따라서 new와 delete를 모두 사용할 필요가 없습니다. 프로그램을 종료한 후 클래스는 모든 CItem 및 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);
 }
//+------------------------------------------------------------------+