Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
RAD XE3+

Как изменить размер динамического массива, переданного по ссылке в функцию?

06.05.2025, 11:20. Показов 3762. Ответов 40
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую!
Почему размер передаваемого по ссылке массива не получается изменить?
Delphi
1
2
3
4
5
6
7
8
9
function ArrResize(var a: Array of Integer): Boolean;
var
  b: Array of Integer;
begin
    Result:= false;
  //SetLength(a, 10); // Error
  SetLength(b, 10);   // Correct
  Result:= true;
end;
[dcc32 Error] Test.dpr(125): E2008 Incompatible types
С процедурой (вместо функции) — то же самое.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.05.2025, 11:20
Ответы с готовыми решениями:

Как изменить размер TImage под текущий размер Picture ?
Доброго времени суток! Есть задача (Delphi 7). В TImage загружается Picture с условиями: Center...

Изменить размерность массива в процедуре, переданного в виде параметра.
Здравствуйте, ВСЕ. Есть процедура procedure Split(var arrResult: array of string); При таком...

Работа с внешним массивом внутри функции переданным как параметр Delphi 10.2 на .Net
Delphi 10.2 на .Net Насколько знаю при передачи массива в процедуру/функцию, передаётся её...

40
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
13.05.2025, 12:43  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от KSergey9 Посмотреть сообщение
Вроде открытый (динамический) массив и так всегда по ссылке передаётся, а не копией
сегодня да, а завтра нет. Я всегда за однозначность (руками указываю, что по ссылке хочу передавать), если синтаксис позволяет.
0
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
13.05.2025, 12:53
Цитата Сообщение от Jack Famous Посмотреть сообщение
сегодня да, а завтра нет
Это либо да, либо нет
Обратную совместимость языка не ломают. Ну т.е. это не случайная фича, а документированная.

Однако согласен, что если уж хочется внутри функции изменять массив - то лучше написать var, ибо программа - она для человека.
1
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
13.05.2025, 19:48
KSergey9, заблуждаетесь. "Открытый" и "динамический" - это совершенно разные вещи.

Открытый массив - это древний костыль паскаля для передачи в подпрограмму статических массивов различной длины.
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
procedure m(x: array of integer);
begin
  x[0] := +100500;
  writeln(x[0])
end;
 
var
  a: array[0..1] of integer;
begin
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  readln
end.
Результат работы программы1
100500
1

Как видите, массив передаётся по значению, как и планировалось.
2
Native x86
Эксперт Hardware
 Аватар для quwy
6860 / 3792 / 1026
Регистрация: 13.02.2013
Сообщений: 11,861
13.05.2025, 19:52
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
Delphi
1
2
3
4
5
var
 a: array[1..2] of integer;
begin
 a[0] := 1;
 writeln(a[0]);
Как у вас это вообще скомпилировалось?
0
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
13.05.2025, 19:56
Ну, в таком виде - никак. Это я пока пост правил с целью повышения наглядности, Вам удалось это заметить.
0
Native x86
Эксперт Hardware
 Аватар для quwy
6860 / 3792 / 1026
Регистрация: 13.02.2013
Сообщений: 11,861
13.05.2025, 19:59
Разговор был немного про другое, KSergey9 зря смешал в одну кучу открытые и динамические массивы, но по сути он прав:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type
  tarr = array of integer;
 
procedure m(x: tarr);
begin
  x[0] := 100500;
  writeln(x[0])
end;
 
var
  a: tarr;
begin
  setlength(a, 1);
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  readln;
end.
Название: delphi1.png
Просмотров: 224

Размер: 1.5 Кб
Но var, я считаю, все равно нужен. Потому что даже профи при беглом изучении исходника о таких особенностях внутренней реализации могут забывать.
1
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
13.05.2025, 20:12
Ну да, динамический массив (в любом случае) передаётся по ссылке, потому что он и есть ссылка. Хоть по значению его передавай, хоть по ссылке - всё равно будет по ссылке. А открытый массив передаётся так, как задано.

И в чём же KSergey9 прав?
0
Native x86
Эксперт Hardware
 Аватар для quwy
6860 / 3792 / 1026
Регистрация: 13.02.2013
Сообщений: 11,861
13.05.2025, 20:25
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
И в чём же KSergey9 прав?
Он сказал ровно то же самое, что и вы. И код, который он процитировал, соответствует именно моему примеру, а не вашему:
Delphi
1
function ArrResize(var a: TIntArray): Boolean;
Только это он написал зря:
открытый (динамический) массив
К остальному претензий быть не должно.
0
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
13.05.2025, 20:37
Вот это
Цитата Сообщение от KSergey9 Посмотреть сообщение
Вроде открытый (динамический) массив и так всегда по ссылке передаётся, а не копией.
неверно.

А претензий у меня вообще ни к чему нет.
0
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
13.05.2025, 22:13
Цитата Сообщение от quwy Посмотреть сообщение
Только это он написал зря:
открытый (динамический) массив
Да, тут я смешал разные термины, признаю.

Добавлено через 1 минуту
Цитата Сообщение от quwy Посмотреть сообщение
Потому что даже профи при беглом изучении исходника о таких особенностях внутренней реализации могут забывать.
Справедливости ради - в книжках про это прям отдельные абзацы текста написаны, на это акцентируется явно внимание где что как передаётся.
0
Native x86
Эксперт Hardware
 Аватар для quwy
6860 / 3792 / 1026
Регистрация: 13.02.2013
Сообщений: 11,861
14.05.2025, 00:35
Цитата Сообщение от KSergey9 Посмотреть сообщение
на это акцентируется явно внимание где что как передаётся
Проблема тут в том, что даже если знаешь учебник наизусть, тип данных ведь может называться как угодно, например TCertificate. И по месту совершенно не ясно, динамический это массив, или статический.
Зато когда видишь это:
Delphi
1
2
3
4
procedure EnableCert(Cert: TCertificate);
begin
  Cert[10] := 0xFF;
end;
, то в голове мгновенно щелкает: "модификация параметра без var, наверняка ошибка".
1
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
20.05.2025, 01:05
Это сообщение содержит глупую ощибку. Смотрите сообщение № 37.

quwy, может возникнуть ошибка, да ещё какая! С умолчаниями насчёт динамического массива всё не так просто.

Есть нехороший подводный камень: если изменить размер динамического массива, передаваемого по ссылке, внутри подпрограммы, то динамический массив по-тихому копируется в новый динамический массив, который по ссылке не может быть возвращён, поскольку ссылка на новый массив не соответствует ссылке в формальных параметрах процедуры. Иными словами, при изменении размера внутри процедуры массив следует передавать по значению, в этом случае новый массив скопируется в исходный при выходе из подпрограммы.

Примеры:

Передаём массив по значению.
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type
  MyDinArr = array of integer;
 
procedure m(var x: MyDinArr);
begin
  SetLength(x, 2);
  x[0] := +100500;
  writeln(x[0])
end;
 
var
  a: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  writeln('Length = ', length(a));
  readln
end.
Результат работы программы1
100500
100500
Length = 2

Всё верно, массив возвращён из процедуры.

А теперь по ссылке:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type
  MyDinArr = array of integer;
 
procedure m(x: MyDinArr);
begin
  SetLength(x, 2);
  x[0] := +100500;
  writeln(x[0])
end;
 
var
  a: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  writeln('Length = ', length(a));
  readln
end.
Результат работы программы1
100500
1
Length = 1

Опаньки... Ошибочка, однако. Да ещё и при большом объёме кода трудно вылавливаемая.

Тот же казус происходит и при изменении длины копии массива без подпрограммы:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type
  MyDinArr = array of integer;
 
var
  a, b: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  b := a;
  //если изменять значения элементов a или b, будут изменяться значения
  //элементов и a, и b, поскольку a и b ссылаются на одно и то же
  SetLength(b, 2); //всё, приехали, вот она, ловушка для неопытных
  //здесь создаётся новый динамический массив, ссылка на него помещается в b,
  //и в новый массив копируется содержимое a,
  //то есть, a и b теперь не ссылаются на одно и то же
  //при изменении длины a будет то же самое: 
  //b будет по-прежнему ссылаться на старое a, a a будет ссылаться на новое a
  //(голосом сумасшедшего учёного) А-ХА-ХА-ХА-ХА!!!
end.
2
Модератор
 Аватар для D1973
9951 / 6486 / 2461
Регистрация: 21.01.2014
Сообщений: 27,481
Записей в блоге: 3
20.05.2025, 07:08
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
Передаём массив по значению.
Delphi
1
2
3
type
 MyDinArr = array of integer;
procedure m(var x: MyDinArr);
Cyborg Drone, по факту все оно так и есть, вот только, если мне мой склероз не изменяет, как раз передача параметра с var - это как раз передача по ссылке, а без var - по значению.
3
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
20.05.2025, 07:58
Цитата Сообщение от D1973 Посмотреть сообщение
с var - это как раз передача по ссылке, а без var - по значению.
Я тоже сразу заметил, в глаза бросается.
0
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
21.05.2025, 02:20
Ну да, попутал... Вообще всё с ног на голову поставил. Видно, мне по ночам лучше спать...
1
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
21.05.2025, 07:59
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
Видно, мне по ночам лучше спать...
Если утром переться на работу, то да.
0
Модератор
10476 / 5771 / 3411
Регистрация: 17.08.2012
Сообщений: 17,528
21.05.2025, 19:26
Работа над ошибками по сообщению #32, а то как-то нехорошо получается.

quwy, может возникнуть ошибка, да ещё какая! С умолчаниями насчёт динамического массива всё не так просто.

Переменная, переданная по значению, является копией глобальной переменной, и, вроде бы, если копию изменить внутри подпрограммы, глобальная переменная изменяться не должна. Но, динамический массив - это ссылка, и изменения элементов массива внутри подпрограммы на самом деле изменяют элементы глобального массива. Получается, что, вроде бы, в случае динамического массива передача по ссылке и по значению - это практически одно и то же. Но, есть нехороший подводный камень. Действительно, если не изменять размер массива, то это и есть одно и то же. Однако, если изменить размер динамического массива, передаваемого по ссылке, внутри подпрограммы, то динамический массив по-тихому копируется в новый динамический массив, который по ссылке не может быть возвращён, поскольку ссылка на новый массив не соответствует ссылке в формальных параметрах процедуры. Иными словами, для гарантированного изменения глобального динамического массива из подпрограммы, его следует передавать именно по значению, а не по ссылке. Вот такой казус.

Примеры:

Передаём массив по значению.
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type
  MyDinArr = array of integer;
 
procedure m(var x: MyDinArr);
begin
  SetLength(x, 2);
  x[0] := +100500;
  writeln(x[0])
end;
 
var
  a: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  writeln('Length = ', length(a));
  readln
end.
Результат работы программы1
100500
100500
Length = 2

Динамический массив, переданный по значению, изменён из процедуры. На первый взгляд, этого быть не может, но так оно и есть.

А теперь по ссылке:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type
  MyDinArr = array of integer;
 
procedure m(x: MyDinArr);
begin
  SetLength(x, 2);
  x[0] := +100500;
  writeln(x[0])
end;
 
var
  a: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  writeln(a[0]);
  m(a);
  writeln(a[0]);
  writeln('Length = ', length(a));
  readln
end.
Результат работы программы1
100500
1
Length = 1

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

Тот же казус происходит и при изменении длины копии массива без подпрограммы:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type
  MyDinArr = array of integer;
 
var
  a, b: MyDinArr;
begin
  SetLength(a, 1);
  a[0] := 1;
  b := a;
  //если изменять значения элементов a или b, будут изменяться значения
  //элементов и a, и b, поскольку a и b ссылаются на одно и то же
  SetLength(b, 2); //всё, приехали, вот она, ловушка для неопытных
  //здесь создаётся новый динамический массив, ссылка на него помещается в b,
  //и в новый массив копируется содержимое a,
  //то есть, a и b теперь не ссылаются на одно и то же
  //при изменении длины a будет то же самое: 
  //b будет по-прежнему ссылаться на старое a, a a будет ссылаться на новое a
  //(голосом сумасшедшего учёного) А-ХА-ХА-ХА-ХА!!!
end.
1
пофигист широкого профиля
4770 / 3206 / 862
Регистрация: 15.07.2013
Сообщений: 18,613
22.05.2025, 01:15
Cyborg Drone,
Цитата Сообщение от D1973 Посмотреть сообщение
Cyborg Drone, по факту все оно так и есть, вот только, если мне мой склероз не изменяет, как раз передача параметра с var - это как раз передача по ссылке, а без var - по значению.
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
Ну да, попутал... Вообще всё с ног на голову поставил. Видно, мне по ночам лучше спать...
И вы опять с ног на голову.
1
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,495
22.05.2025, 02:08
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
Передаём массив по значению.
Delphi
1
procedure m(var x: MyDinArr);
...
Цитата Сообщение от Cyborg Drone Посмотреть сообщение
А теперь по ссылке:
Delphi
1
procedure m(x: MyDinArr);
А не наоборот? var по ссылке передаёт, же?
Одинаково с № 32 получилось.
1
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
22.05.2025, 08:44  [ТС]
Вот так у меня прекрасно работает
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//-------------------------------------------------------------------------------------------------
function StrANSI_Split_ToByte(var Str: AnsiString; Sep: AnsiChar; var aBt: TArray<Byte>; NoZero: Boolean = False): Boolean;
var
  a, c, d, f, n : LongWord;
  i, m                  : Integer;
label
  nx;
begin
  Result:= False; n:= 0; f:= 1;
  c:= Length(Str); a:= Length(aBt);
  if (a = 0) then begin a:= c Div 3; SetLength(aBt, a); end;
  m:= Low(aBt) - 1;
 
  for c:= 1 to c do
  begin
    if (Str[c] = Sep) then
    begin
      d:= c - f; if (d < 1) then GoTo nx;
      i:= StrToIntDef(AnsiMidStr(Str, f, d), -1);
      if ((i < 0) or (i > 255)) then GoTo nx;
      if ((i = 0) and NoZero) then GoTo nx;
      if (a = n) then begin a:= a * 2; SetLength(aBt, a); end;
      Inc(n); Inc(m); aBt[m]:= i;
nx:     f:= c + 1
    end;
  end;
 
  if (n = 0) then Exit;
  SetLength(aBt, n); Result:= True;
end;
//-------------------------------------------------------------------------------------------------
var
    a: TArray<Byte>;
  s: AnsiString;
  c: AnsiChar;
  w: LongWord;
  b: Boolean;
label
  nx;
begin
  s:= ',,1,2,-345,a,2e2,,tyyu,,,111,,222,,333,,'; c:= ',';
  b:= StrANSI_Split_ToByte (s, c, a); if not b then goto nx;
  for w:= Low(a) to High(a) do begin WriteLn(IntToStr(w) + '_' + IntToStr(a[w])); end;
nx:
  WriteLn(b); ReadLn;
end.
//-------------------------------------------------------------------------------------------------

Print:
0_1
1_2
2_111
3_222
TRUE
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
22.05.2025, 08:44

Сохранение изменений, произведённых в функции с переменной, переданной в эту функцию в качестве параметра.
Всем привет. Собственно, как это можно сделать? :) Пробовал переменную делать и локальной, и...

Создать функцию, которая бы возвращала кол-во бит в переданном ей байте
Создать ФУНКЦИЮ которой возвращает кол-во бит переданном его в байте. function bitcut(x:byte):byte;

Запись значения по указателю, переданному в качестве аргумента в функцию
Всем привет! Помогите плиз с проблемкой, либо скажите что это не реально)) Добавлено через 2...

Функция: определить, является ли переданная в качестве параметра буква гласной
Добрый день. Нужна помощь в решении задачи. Описать функцию, определяющую, является ли переданная...

Как написать счетчик переданных байт интернета на Delphi7? Какой компонент использовать?
Как написать счетчик переданных байт интернета на Delphi7? Какой компонент использовать?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru