Непонятки с массивами строк

 
Возникла необходимость передать строки из dll в некий строковый массив в терминале.
В документации (DLLSample), дескрипторы строк описаны как:
struct MqlStr
{
int len;
char *string;
};

Т.е. string - указатель на строку, завершенную нулем, и len - длинна этой строки.
Именно так я и передавал:

static char test[]="some string"; //строка статически расположена в сегменте данных dll
..........................................
void PutString(MqlStr *arr, int n)
{
arr[n].string=test;
arr[n].len=strlen(test);
}

В результате программа висла. Передав этой функции проинициализированный в эксперте массив строк,
и посмотрев в отладчике, что передается, с удивлением обнаружил, что во всех строках, поле len равно 0 !
У неинициализированного массива так же, во всех строках len=0, но там еще и string=0. Увидев это, перестал
присваивать значение полю len. Т.е. :
void PutString_1(MqlStr *arr, int n)
{
arr[n].string=test;
}

После этого всё заработало. Вопрос, правильно ли я поступил ? Действительно ли нужно лишь копировать в поле string
указатели, а len оставлять без изменения ?
 
У нас С-строки, оканчивающиеся нулем. Не меняйте размер строк.
 
Ренат, да это понятно из вашего примера. Непонятно назначение поля len. Вроде по логике вещей, это длинна строки. Тем не менее, и в инициализированном и в неициализированном массивах, это поле равно нулю. Если туда закидывается реальная длинна строки, всё виснет. Если это поле остается равным нулю, всё работает, по крайней мере в пределах моего тестирования. У меня билд 198. Не знаю, что у вас было в более ранних версиях. Но если способы обработки строковых массивов, либо механизмы импорта изменились, это желательно отразить в документации. Просто то, что сейчас по поводу строковых массивов есть, скорее вводит в заблуждение, чем помогает. Прошу только, не в обиду. По себе знаю, как программеры ненавидят документировать :)
 
Поле len используется нами для собственных нужд и указывает на способ работы с памятью этой строки. Поэтому Вам лучше не трогать его - это никак не повлияет на работоспособность.
 
Ренат, большое Вам спасибо. Тогда вопрос снят. А то я уже глазам своим верить перестал, сравнивая то, что видел в отладчике, и то, что предполагал, исходя из документации. Всё-таки вам на будущее лучше это явно отразить в печатном виде :)
 
Renat писал (а):
Поле len используется нами для собственных нужд и указывает на способ работы с памятью этой строки. Поэтому Вам лучше не трогать его - это никак не повлияет на работоспособность.

А можно прояснить - когда и как выделяется буфер под строку, и когда и как он освобождается?
В приведенном выше примере, строка лежит в сегменте данных, и по идее, при попытке освобождения такой строки (а она ведь должна быть?) менеджер памяти должен выдать ошибку.
Можно поподробнее про "Поле len используется нами для собственных нужд и указывает на способ работы с памятью этой строки..."?
Как же все таки правильно вернуть строку из dll?
 
Ладно, спрошу по другому... ;)
Renat, если в советнике будет сформирована строка длиной X символов, затем она передается в DLL (как pchar), и внутри DLL в эту строку поверх записывается строка длиной Y символов (Y < X) формата ASCIIZ.
Так можно делать?
 
Demax:
Ладно, спрошу по другому... ;)
Renat, если в советнике будет сформирована строка длиной X символов, затем она передается в DLL (как pchar), и внутри DLL в эту строку поверх записывается строка длиной Y символов (Y < X) формата ASCIIZ.
Так можно делать?
Да, Вы можете без проблем модифицировать буфер строки, переданный в DLL. Только будьте осторожны с передачей статических строк.
 
Renat:
Demax:
Ладно, спрошу по другому... ;)
Renat, если в советнике будет сформирована строка длиной X символов, затем она передается в DLL (как pchar), и внутри DLL в эту строку поверх записывается строка длиной Y символов (Y < X) формата ASCIIZ.
Так можно делать?
Да, Вы можете без проблем модифицировать буфер строки, переданный в DLL. Только будьте осторожны с передачей статических строк.
А можете показать пример передачи статических строк который не следует делать

Может быть это имеется ввиду?

char* statstr = "static string";

void func1(MqlStr* strarr, int n) {
strcpy(strarr[n].string, statstr);
}

или

void func2(char* str) {
strcpy(str, statstr);
}

По уазателю strarr[n].string должна быть выделена память уже, иначе будет ошибка доступа по неверному адресу если strarr[n].string строка будет короче чем statstr.

Кстати, а вот код который привёл автор статьи может привести к утечке памяти, если, например, строка в массиве arr[n].string уже есть массив char при предаче его в функцию DLL.
То есть передавая массив строк MQL4 string[] с какими-то значениями, а затем присваивая новое значение указателю на строку в DLL мы можем привести к утечке памяти при вызове эксперта и функции из DLL на каждый новый тик. Прежняя то строка не удаляется же при этом. Или я заблуждаюсь?

void PutString(MqlStr *arr, int n)
{
arr[n].string=test;
}
 
По статическим строкам - это любые _прямые_ операции над статическими строками, заключенными в кавычки.

Кстати, а вот код ниже может привести к утечке памяти, если, например, строка в массиве arr[n].string уже есть массив char
То есть передавая массив строк string[] с какими-то значениями, а затем присваивая новое значение указателю на строку мы можем привести к утечке памяти при вызове эксперта и функции из DLL на каждый новый тик. Или я заблуждаюсь?

void PutString(MqlStr *arr, int n)
{
arr[n].string=test;
}

Это однозначно приведет к утечке и крупным проблемам. При разовом или редком использовании такого метода может терминал и не упадет, но при достижении определенного уровня все обязательно заглючит.

Важно знать, что из DLL можно _изменять_ содержимое строки в пределах доступного размера, но нельзя подменять строковые буферы. К сожалению, нельзя даже сделать free/delete, а потом malloc/new, так как память для строк выделяется не в стандартном хипе через malloc/new, а в специальном строковом пуле.
 
Renat:
По статическим строкам - это любые _прямые_ операции над статическими строками, заключенными в кавычки.

Кстати, а вот код ниже может привести к утечке памяти, если, например, строка в массиве arr[n].string уже есть массив char
То есть передавая массив строк string[] с какими-то значениями, а затем присваивая новое значение указателю на строку мы можем привести к утечке памяти при вызове эксперта и функции из DLL на каждый новый тик. Или я заблуждаюсь?

void PutString(MqlStr *arr, int n)
{
arr[n].string=test;
}

Это однозначно приведет к утечке и крупным проблемам. При разовом или редком использовании такого метода может терминал и не упадет, но при достижении определенного уровня все обязательно заглючит.

Важно знать, что из DLL можно _изменять_ содержимое строки в пределах доступного размера, но нельзя подменять строковые буферы. К сожалению, нельзя даже сделать free/delete, а потом malloc/new, так как память для строк выделяется не в стандартном хипе через malloc/new, а в специальном строковом пуле.

то есть если хотим передавать строки в эксперт из DLL то надо заранее проинициализировтаь строки максимальным значением типа

Эксперт:
 
void testStringFunc() {
  string[] strArray = {"ccccccccccccccc", "ccc"};
  dllFunc(strArray, 2);
  Print("strArray[0] = ", strArray[0]);
  Print("strArray[1] = ", strArray[1]);
}
 
DLL:
 
EXP void __stdcall dllFunc(MqlStr* strArray, int n) {
  strcpy(strArray[0].string, "maximum 14 char");
  strcpy(strArray[1].string, "123");
}
Причина обращения: