SetLength — Процедура Delphi


SetLength — Процедура Delphi

When changing the size of a string StringToChange, the new size NewLength may be smaller, the same or larger than the existing string. In all cases, the size is in characters, and a new string is created regardless.

If the string is shorter, it gets truncated. If longer, the extra characters are not initialised. This can create odd effects — see the first example.

A dynamic array is one that is not declared with a fixed size. Such a declaration creates a pointer only. Even a multi-dimensional dynamic array starts as a single, unitialised pointer. A multidimensional array is really just a single dimensional array that has arrays as elements.

SetLength sets the length of the dimensions Dim1Length, Dim2Length . of the ArrayToChange. This may be performed multiple times — not just on an unitialised array. Subsequent calls will lose data, or add extra space. This extra space is only initialised if it contains strings, interfaces, or Variants.

SetLength — Процедура Delphi

Sabj:
Для примера

for i:=1 to x do s:+s+»a»;

нужно ли тут применять SetLength rf;lsq раз при увеличении s если x неизвесно (например в цикле While)? Или если s элемент динамически созданной записи?
Т.е. когда нужно когда не нужно и почему.
Заранее благодарен.

Для твоего случая — не нужно.

нет.
в данном конкретном случае не нужно — об этом позаботится компилятор, вставив в результирующий код неявный вызов SetLength()

Надо только перед обращением к символу строки по индексу, и только в том случае, если индекс превышает длину.
По окончании работы со строкой можно освободить память, устанавливаяя нулевую длину строки.

Те если вот это правильно:

s:=»asd»;
SetLength(s,4);
s[4]=»f»;

Dj всех остальных случаях SetLength не применяется.

>MegaVolt © (29.05.03 15:25)
Не думаю что есть точный рецепт применения SetLength.
Всё зависит от конкретного случая.

в данном случае — да, правильно. т.е. как один из правильных вариантов явного увеличения памяти, отводимой под буфер строки.

если же не предпринять ни этого ни какого либо иного варианта увеличения буфера, есть ненулевой риск получить AV-исключение.

Правда, иногда еще укорачивают строку при помощи SetLength, если хвост больше не нужен.

А как мне догадыватся что в этом случае нужно а тут не нужно

Сам должен думать, что тебе надо по твоему алгоритму.
Если «Volt» больше не нужен, то: s:=»MegaVolt»; SetLength(s,4);
Когда будешь пользоваться чем-нибудь, изменяющим отдельные символы внутри строки, типа FillChar или Move, действуй аналогично присваиванию s:=»f»;

Обычно SetLength для строк используется вместо буфера (array[0..lenbuf-1]) при применении процедуры Move., но есть еще множество вариантов. При объединении строк Delphi автоматически выделит нужную память.

2MegaVolt
см Sha © (29.05.03 15:19)

Например.
SetLength(S, 15);
for i := 1 to 15 do
S[i] := chr(i+ord(«A»));

В форуме далеко не редки ситуации, когда для целей «догадывания» используются другие, альтернативные места)

а не надо догадываться !
просто надо представлять в каждый момент времени, что происходит со строкой ПЕРЕД операцией над ней и каково будет ее состояние ПОСЛЕ той или иной операции, которая, несмотря на внутреннюю схожесть, выглядеть с т.з. Паскаль-текста может по-разному . и при неуверенности сразу же «лезть» в исходники System и SysUtils

А если я применяю такую запись

S:=copy(s,x,y);

то не нужно как я понимаю? Или всё таки нужно если размер результирующей строки меньше исходной?

>MegaVolt © (29.05.03 15:56)

If Index is larger than the length of S, Copy returns an empty string or array.

простейшее объяснение — никаких явных преобразований типов между результирующим типом (ф-ция возвращает string) и типом переменной s: string перед присвоением не требуется и не происходит, поэтому компилятор самостоятельно заботится о :

— перераспределении памяти под переменную s, чтобы размер ее буфера соответствовал размеру буфера строки, возвращаемой из ф-ции;

— копировании из буфера возвращаемой строки в буфер переменной s;

— уничтожении результирующей строки с автоматическим освобождением памяти под ее буфер;

Я не про индех больше длинны строки а про то :

s:=»MegaVolt»;
s:=Copy(s,1,4);

в результате строка результата стала меньше изначальной строки вот я и спрашиваю нужно самому уменьшать строку под размер новой или дельфи сам? И кстати исходников функции Copy нету в System и SysUtils :(

и вообще я не понимаю, не ужели трудно поэкспериментировать?
есть такая функция Length мог бы и посмотреть сам


> исходников функции Copy нету в System и SysUtils :(

есть) . procedure _Copy(. ) смотри.

но setlength() ты там не увидишь, в ее теле, ибо этот вызов компилятор вставляет неявно


> но setlength() ты там не увидишь, в ее теле, ибо этот вызов
> компилятор вставляет неявно

А если включить Use debug DCUs ? Можно кое-что увидеть, и даже
очень интересного, особенно если прогнать построчно. )

Илон Маск рекомендует:  Что такое код basename

Например, ты принял из какой-нибудь функции (напр, из dll) буфер buff типа pchar и количество символов в нем хранящихся charcount. Задача — сделать из нее строку (string) S.

Вариант1:
S:=»»;
while charcount>0 do
begin
S:=S+buffer^;
inc(buffer);
dec(charcount);
end;

Вариант2:
SetLength(S, charcount);
move(buffer^, s[1], charcount);

Угадай с трех раз — какой из вариантов будет работать быстрее и занимать меньше кода?

Второй вариант раз в 6 быстрее :) Начинаю понимать.

Кстати вместо второго варианта можно написать? Или нет?

s:=PChar(buffer);

>MegaVolt © (29.05.03 17:54)
Можно, но зачем ? Buffer и есть PChar.

2(MegaVolt) Вот и можешь получить другую строку намного большую пока не найдется #0. PCHAR можно использовать и всесто Pointer для более простой арифметики над указателями. Надо быть уверенным при ее использовании, что это указатель на нуль терминированную строку. Простой пример при использовании со стримами.
Str.Read(TypeVal,SizoOf(TypeVal));
If TypeVal=IdStroka Then
Begin
Str.Read(LenStr,SizoOf(LenStr));
SetLength(str,lenStr);
Str.Read(str[1],LenStr);
end;

SetLength как раз можно использовать для ускорения работы со строками в такоом случае:

1.
var
s: String;
i: Integer;
begin
s := «»;
for i := 0 to 255 do
begin
s := s + Chr(i);
end;
end;

2.
var
s: String;
i: Integer;
begin
SetLength(s,256);
for i := 0 to 255 do
begin
s[i] := Chr(i);
end;
end;

Второй пример будет работать быстрее из-за того, что не надо память перераспределять в цикле.

SetLength — Процедура Delphi

Sets the length of a string or dynamic-array variable.

S is a Delphi string or dynamic-array variable.

NewLength is the new number of characters or elements in S.

For a short-string variable, SetLength simply sets the length-indicator character (the character at S[0]) to the given value. In this case, NewLength must be a value between 0 and 255.

For a long-string or dynamic-array variable, SetLength reallocates the string or array referenced by S to the given length. Existing characters in the string or elements in the array are preserved, but the content of newly allocated space is undefined. The one exception is when increasing the length of a dynamic array in which the elements are types that must be initialized (strings, Variants, Variant arrays, or records that contain such types). When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil.

For dynamic arrays, SetLength may take more than one length parameter (up to the number of array dimensions). Each parameter specifies the number of elements along a particular dimension.

Following a call to SetLength, S is guaranteed to reference a unique string or array—that is, a string or array with a reference count of one. If there is not enough memory available to reallocate the variable, SetLength raises an EOutOfMemory exception.

Делфи. Не работает Setlength

Господин ПЖ

>а затем ломается на 409 шаге.

я бы тоже сломался

Господин ПЖ H A D G E H O G s

во первых есть объект list, он динамический, с ним так можно работать (он может располагается в прерывистом диапазоне памяти).

объект array — статический, под него выделяется единый кусок памяти, если в единый кусок не влезает — беда.

H A D G E H O G s H A D G E H O G s Ненавижу 1С H A D G E H O G s H A D G E H O G s H A D G E H O G s H A D G E H O G s

(20) извращи.
Программист либо должен знать конечный размер либо пользовать связный список.

Tlist кстати, красивый пример компромисс.

(23) Код настолько огромен, что его и не выложить. Примерно такой:
ююю
BackCount := 0;
while (BackCount 2) do
begin
PlaceOfError := 30;
if PointOfIntersectionLines(RoadLines[Linecount], RoadLines[Linecount — BackCount — 2]) then
begin
Range := BackCount + 2;

PlaceOfError := 31;
for N := Linecount — BackCount — 1 to POintCount — 1 — Range do
Polypoints[N] := Polypoints[N + Range];
PlaceOfError := 317;
POintCount := POintCount — Range;
PlaceOfError := 318;
setlength(Polypoints, POintCount);

PlaceOfError := 319;
Linecount := Linecount — BackCount — 3;

end;
PlaceOfError := 321;
inc(BackCount);
PlaceOfError := 322;
end;
.
ошибка на этом шаге
setlength(Polypoints, POintCount);

AnsiString в Delphi

Строки в Delphi представляют собой последовательность символов. Можно разделить на 4 типа строки в Делфи:

  1. ShortString (максимальная длина – 255) используется для обратной совместимости. Нулевой символ отсутствует в конце.
  2. AnsiString (максимальная длина ˜2 Гб) используется для символов ANSI. Нулевой символ присутствует в конце.
  3. String (255 символов или до ˜2 Гб) используется для ANSI или Unicode. Нулевой символ может присутствовать или не присутствовать в конце.
  4. W >

Подробнее хочу остановиться на строковых типах ShortString и AnsiString. Они различаются между собой организацией хранения в памяти. Строки типа ShortString хранят в своем нулевом байте число символов в строке, а в последующих байтах – сами символы (не более 255). Поэтому, если Q – строка типа ShortString, то Ord(Q[0]) – то же, что и Length(Q), возвращает длину строки. Присваивание значения Q[0] соответствует вызову функции SetLength, которая устанавливает длину строки.

Переменная типа AnsiString является указателем на динамически выделяемую область памяти, в которой хранится строка. Может существовать несколько переменных, которые ссылаются на одну и ту же строку. В этом случае в памяти хранится только один экземпляр строки. Это экономит ресурсы. В случае, если строка равна 0, то этот указатель равен nil и память под строку не выделяется. Если же строка не пустая, то в выделенной памяти хранится сама строка, ее длина и число ссылок (переменных) ссылающихся на данную строку. Если переменной типа AnsiString присваивается новое значение, то число ссылок в прежней строке уменьшается на единицу, а в новой – увеличивается на единицу. Когда число ссылок на строку становится равным 0, то строка уничтожается, освобождая место в памяти.

Длинные строки типа AnsiString

Переменные этого типа объявляются обычным образом:

Var Q1: AnsiString;


Q2: string;

Объявление глобальных переменных или типизированных констант можно сочетать с инициализацией, причем нулевой символ в конце строки добавляется автоматически.

Var Q1: AnsiString = ‘текст’;

Q2: string = ‘начальный тест’;

Доступ к отдельным символам строки осуществляется как к символьному массиву по индексу (индекс отсчитывается от 1, а во всех других типах длинных строк индексы отсчитываются от 0). Для строки Q1 выражение Q1[2] возвращает символ строки ‘е’ – второй символ строки. Если индекс выходит за рамки числа символов в строке, то возвращается нулевой символ ‘#0’.

Функция Length(Q1) возвращает число символов строки, не считая нулевого символа. В данном случае Length(Q1) вернет 5.

Procedure SetLength(var Q; NewLength: Integer);

задает новый размер NewLength строки Q. Если NewLength меньше числа символов в строке, то текст строки усекается до указанного числа символов, иначе (т. е. больше), то прежний текст сохраняется, а после него записываются нулевые символы.

Для обработки строк типа AnsiString существует ряд библиотечных функций.

. delphi максимальный размер строки максимальная длина строки в delphi равна размер ansistring delphi ansistring макс длина delphi ansistring

SetLength — Процедура Delphi

Всем доброго времени суток. В стандартном хелпе ответа не нашел

Ну, насколько я понял a := nil как раз и приведет к утечке. Не помню уже где, я на Делфи уже несколько лет нормально не программировал, но рекомендация была — делать вложенные циклы для освобождения памяти:

Soul
Есть множество техник.
0. Открыть system.pas и посмотреть как устроена процедура SetLength.
Я обычно открывают модуль так пишу system ставлю на него каретку и нажимают ctrl+Enter. Дальше разбирать код там половина паскаль половина ассемблер.

1. Открыть Debug Window -> CPU и пошагаво пройтись по функции. В окне CPU отладка пошагова может заходить в системные процедуры и функции библиотек. В отличии от обычной пошаговой, которая работает только в *.pas модулях.

2. Отследить утечки. Для отслеживания утечек памяти есть разные утилиты. Для Delphi 7 надо поставить менеджер памяти FastMM.
И использовать ReportMemoryLeaksOnShutdown. А да в последующих версиях Дельфи этот менеджер стал основным.

Тут совет потренироваться. А то без тренировки сразу можно не понять результат. Когда я первый раз этим делом занимался не сразу врубился о том что там написано.

3. Взять профиловщик. У профиловщиков богатый функционал.
а) Они также умеют находить утечки.
б) Можно отследить какие процедуры и функции где вызывались, сколько раз и их вложенность.

SetLength — вызов процедуру затрагивает элементы чужого массива

Здравствуйте!
При вызове SetLength в процедуре, изменяется массив, который передан в процедуру по var..
Вот код:

uses
SysUtils;
Const
CN = 4;
CK = 999;
Type
TSortArr = array of integer;

procedure SortCount(var A:TSortArr;n,k:integer);
var
B,Count:TSortArr;
begin
B := A;
SetLength(Count,k);
end;

Var
A:TSortArr;
i:integer;

SetLength(A,CN);
// Set Array
for i:=0 to CN do
begin
A := random(CK);
write(A,’ ‘);
end;

// Ouput
writeln;
for i:=0 to CN do
write(A,’ ‘);

До вызова SortCount, массив имеет элементы:
0 31 860 202 272
0 31 860 202 4010

После SetLength(Count,k); такое и происходит. Может кто подскажет, что здесь такое и что делать.

С переданной A, и назначенной Count — ничего дальше не делается, то есть после завершение процедуры, они пропадают из памяти. . ?)
Надо наверно вот так

SetLength — Процедура Delphi

284 просмотра

3 ответа

20 Репутация автора

Я хочу реализовать свою собственную функцию MySetLength (), которая могла бы работать точно так же, как и оригинальная SetLength () (из delphi 6) для массивов, за исключением того, что я хотел бы передавать параметры с плавающей точкой как измерения (а затем, в конце концов, округлить его внутри моей функции, перед тем как вызов оригинальной Setlength ()). например:

где A может иметь любое количество измерений и может быть любого типа (строки или числа с плавающей запятой)

Ответы (3)

2 плюса

537247 Репутация автора

Это будет невозможно реализовать и заставить его работать точно так же, как это SetLength происходит, потому что SetLength это встроенная функция, которая имеет поддержку компилятора и среды выполнения. Вот как функция может принимать произвольные массивы и строковые типы и принимать произвольные числа аргументов измерения. Только поставщик компилятора может сделать такую ​​функцию.

У вас действительно нет надежды на создание чего-нибудь полезного, что соответствовало бы спецификации в вопросе. Безусловно, лучший подход — вызывать SetLength напрямую и применять Round функцию к любым аргументам, которые необходимо округлить.

2 плюса

368860 Репутация автора

На ум приходят перегрузки и дженерики:

Если вы используете версию Delphi, которая не поддерживает Generics, вы не можете перегрузить типы элементов массива в общем, но вы все равно можете перегружать массивы, если используемые типы элементов ограничены, например:

Как видите, реализация SetLength() для одного String проста, но реализация SetLength() для массивов может быть довольно сложной, в зависимости от типа используемых массивов. Это решение настолько близко, насколько вы можете ввести код пользователя, не прибегая к RTTI, поэтому вы можете DynArraySetLength() напрямую вызывать функцию RTL .

2 плюса

19919 Репутация автора

Зачем усложнять вещи, пытаясь обойти проблемы с перегрузкой или заменой встроенной?

Почему бы не реализовать стратегию округления, которую вы бы использовали в своем заменяющем SetLength, и просто включить ее в свои вызовы встроенной функции, где это уместно?

Разумеется, вы сохраняете все возможности SetLength , в том числе возможность применять правила границ измерений для двойных значений к нескольким измерениям, где это необходимо:

Где ArrayDim (или поименованный, как вам удобно ) — это функция, которая реализует вашу стратегию округления и возвращает соответствующее измерение массива ( целое число ) для указанного ввода ( double ).

Почему вы делаете это, а не просто используете Round () ?

Ответ заключается в том, что Round () в Delphi использует особую стратегию округления, которая называется Bankers Rounding . Это означает, что n.5 может округляться вверх или вниз , в зависимости от значения n .

Даже если эта стратегия округления подходит для ваших нужд в настоящее время, вы должны реализовать функцию, чтобы явно применять конкретную стратегию округления, подходящую для измерений массива, и использовать ее в вызовах SetLength () .

Это не только гарантирует, что вы применяете правильную стратегию округления в каждом случае, это также означает, что если вам когда-либо понадобится или вы решите изменить свою стратегию округления для измерений массива, вам нужно только изменить свою функцию , а не все вызовы SetLength () используя эту функцию.

SetLength — Процедура Delphi

Здравствуйте, Charly22, Вы писали:

C>Здравствуйте!
C>Уже давно работаю над программой, которую начинал писать на Delphi 7. Программа разрослась, и транслировать ее для новых IDE в настоящее время проблематично.
C>Недавно столкнулся с проблемой в процедуре SetLength(): при повторном вызове этой процедуры с целью установления нужного размера динамического массива программа выдает ошибку AV.
C>Мне сказали, что в Delphi7 процедура SetLength() работает не всегда корректно.

C>Я решил написать отдельную DLL в XE2. В ней только одна функция, изменяет размер входного массива. Вот код из DLL:

Менеджер памяти один и тот же? Если нет, то AV абсолютно законен (один менеджер не может освободить память, принадлежащую другому менеджеру).

От: Charly22
Дата: 28.11.16 19:23
Оценка:

Здравствуйте!
Уже давно работаю над программой, которую начинал писать на Delphi 7. Программа разрослась, и транслировать ее для новых IDE в настоящее время проблематично.
Недавно столкнулся с проблемой в процедуре SetLength(): при повторном вызове этой процедуры с целью установления нужного размера динамического массива программа выдает ошибку AV.
Мне сказали, что в Delphi7 процедура SetLength() работает не всегда корректно.

Я решил написать отдельную DLL в XE2. В ней только одна функция, изменяет размер входного массива. Вот код из DLL:

А вот кусок кода из основной программы, вызывающий из DLL функцию SetLen:

Что же я не так делаю? Или можно как-то по-другому решить проблему с SetLength() ? Спасибо.

От: BlackEric http://black-eric.lj.ru
Дата: 29.11.16 10:15
Оценка:

Здравствуйте, Charly22, Вы писали:

1. Я не припомню особых проблем с SetLength в Д7.
2. Покажите ваш код работы с массивом полностью, как он объявлен и что вы с ним делаете.

От: Danchik
Дата: 30.11.16 11:38
Оценка:

Здравствуйте, Charly22, Вы писали:

[Skip]

C> Что же я не так делаю? Или можно как-то по-другому решить проблему с SetLength() ? Спасибо.

ASD-SOFT

Программирование. Теория и практика.

Новые возможности работы с динамическими массивами в Delphi XE7

Здравствуйте уважаемые коллеги!

В версии XE7 при работе с массивами появились следующие возможности:
— Инициализировать динамический массив при помощи константы
— Объединять массивы при помощи оператора «+»
— Использовать методы Insert, Delete, и Concat для динамических массивов

Давайте посмотрим несколько примеров использования новых возможностей…

Инициализация.
Раньше приходилось писать следующие конструкции для создания динамического массива:

Где SetLength(dynArray, 3) — Задать длину массива равной 3.

Теперь можно сделать намного проще:

Намного удобнее, не правда ли?

Объединение массивов при помощи оператора «+» выглядит следующим образом:

После этой манипуляции массив dynArray будет включать в себя элементы обоих массивов: [1,2,3,4,5,6].

Методы Insert, Delete и Concat:

Данные возможности работают не только с массивами простых типов. Вы можете использовать любой тип. Например, массив форм TForm:

Обратите внимание на конструкцию for — in, которая предоставляет доступ к каждому элементу массива в цикле.

Нововведения действительно интересные и полезные. И позволят сильно облегчить работу с динамическими массивами.

Илон Маск рекомендует:  Операции инкрементадекремента
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL