Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 15.12.2013, 21:06   #1
frosich
Пользователь
 
Регистрация: 10.03.2009
Сообщений: 15
По умолчанию Использование нетипизированного указателя для передачи массива.

Здравствуйте уважаемые форумчане!
Никак не могу понять почему не работает конструкция вида:
Код:
procedure MakeArray(P: pointer);
var
  loc_a: array of integer;
  i,n: integer;
begin
  Pointer(loc_a):=P;
  n:=50+random(101);
  SetLength(loc_a,n);
  for i:=0 to n-1 do
    loc_a[i]:=random(101);
  Pointer(loc_a):=nil;
end;

var
  a: array of integer;

begin
  MakeArray(Pointer(a));
 {Длина массива по прежнему ноль}
  ...
end;
Данный пример написан на подобии используемого куска кода, где наблюдается проблема.

Объявления типа
Код:
type
  intarr = array of integer;
не использую, поскольку так и не нашёл как грамотно привести типы в данном случае intarr и array of integer.
frosich вне форума Ответить с цитированием
Старый 15.12.2013, 21:35   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Можно, но не так. А лучше более безопасным способом MakeArray1
Код:
type TMyArray = array of Integer;
     PMyArray = ^TMyArray;

procedure MakeArray(P: pointer);
var p1: PMyArray;
    i,n: integer;
begin
  p1:=p;
  n:=50+random(101);
  SetLength(p1^,n);
  for i:=0 to n-1 do p1^[i]:=random(101);
end;

procedure MakeArray1(var MyArray: TMyArray);
var i,n: integer;
begin
  n:=50+random(101);
  SetLength(MyArray,n);
  for i:=0 to n-1 do MyArray[i]:=random(101);
end;

var a: array of integer;
    b: TMyArray;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Randomize;
  MakeArray(Addr(a));
  Label1.Caption:=IntToStr(High(a));
  MakeArray1(b);
  Label2.Caption:=IntToStr(High(b));
end;
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 15.12.2013, 22:30   #3
frosich
Пользователь
 
Регистрация: 10.03.2009
Сообщений: 15
По умолчанию

А можно, если не трудно, по подробнее расписать почему именно так нужно, а то первый представленный ранее вариант работал до тех пор, пока размер массива был известен заранее.
Просто хочется разобраться.
Второй вариант конечно самый популярный в интернете, но, как я писал это лишь пример ситуации из реального кода, в котором не хотелось бы везде менять
Код:
array of integer
на
Код:
TMyArray
frosich вне форума Ответить с цитированием
Старый 16.12.2013, 05:42   #4
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

array of - это magic конструкция дельфи аналогичная string... под "магичностью" подразумевается автоматическое управление временем жизни, контроль количества ссылок и куча кода которую компилятор добавляет скрытно для обеспечения этой автоматичности...
обращаясь к такому массиву как поинтеру в MakeArray ты нарушаешь подсчет ссылок (нехватает 1 ссылки), и по выходу из процедуры массив уничтожается так как считает что он никому не нужен. а далее ты работаешь с трупом
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 16.12.2013, 11:34   #5
frosich
Пользователь
 
Регистрация: 10.03.2009
Сообщений: 15
По умолчанию

Я чего-то не понимаю, я же вызываю
Setlength()
я думал что при этом счётчик ссылок увеличивается на единицу, а перед завершением процедуры перевожу указатель локального массива на nil.
Мне казалось, что при завершении процедуры счётчик ссылок исходного массива не должен измениться, так как локальный массив уже не связан с глобальным.
То есть после работы MakeArray, как мне казалось должен был остаться кусок памяти от Pointer(a)-12 до Pointer(a)+length(a)-1. Который должен трактоваться программой как массив.
Вопрос: где теряется ссылки, и что не так в рассуждениях?
frosich вне форума Ответить с цитированием
Старый 16.12.2013, 13:25   #6
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

в первом посте не инициализированная а передается, и такой же остается после MakeArray т.к. параметр не var
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 17.12.2013, 20:08   #7
frosich
Пользователь
 
Регистрация: 10.03.2009
Сообщений: 15
По умолчанию

Цитата:
в первом посте не инициализированная а передается, и такой же остается после MakeArray т.к. параметр не var
Передаётся не a, а указатель на первый элемент этого массива. Зачем его вообще менять? Он соответствует определённой ячейке памяти. Указатель локальной переменной подменяется указателем глобальной. Затем локальная переменная инициализируется. И перед завершением процедуры указатель опять подменяется на nil, чтобы выделенную память не очистил сборщик мусора. По логике вроде должно работать. Хочется понять что же всё-таки не так.
frosich вне форума Ответить с цитированием
Старый 20.12.2013, 01:28   #8
frosich
Пользователь
 
Регистрация: 10.03.2009
Сообщений: 15
По умолчанию

Всем спасибо! Разобрался в чём проблема. Процедура
Код:
SetLength()
меняет адрес локального массива, который при этом перестаёт быть связан с глобальным.
Кстати, по этой же причине работает только процедура
Код:
MakeArray1
из представленных Аватар-ом.
Видимо Slym как раз имел ввиду необходимость передать указатель с параметром var и изменить его.

Последний раз редактировалось frosich; 20.12.2013 в 01:54.
frosich вне форума Ответить с цитированием
Старый 20.12.2013, 12:24   #9
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Цитата:
Кстати, по этой же причине работает только процедура MakeArray1
Не правильно. Работает и MakeArray из #2
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 20.12.2013, 13:24   #10
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

вот так и появились поинтеры на поинтеры
int **i;
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Передача указателя массива в фунцию. firephenix Общие вопросы C/C++ 4 09.07.2011 06:07
определения массива как указателя jon888 Общие вопросы C/C++ 2 09.05.2011 13:00
Использование указателя socket.Data TServerSocket _PROGRAMM_ Работа с сетью в Delphi 0 13.02.2011 19:26
Массив с использование указателя Seferus Общие вопросы C/C++ 1 02.11.2010 19:54
Инкремент для указателя массива структур Valter Общие вопросы C/C++ 6 31.05.2010 18:30