Работа с указателями

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Работа с указателями

Сообщение SeZuka » 08.08.2013 10:04:59

Проясните как работать с указателями на массив.
Имеем:
Код: Выделить всё
type
  TIntArray = array if integer;
  PIntArray = ^ TIntArray;
var
  IntArray: PIntArray;
begin
  IntArray = GetMem(100*SizeOf(integer));

Как обращаться к элементам массива?
Код: Выделить всё
  IntArray^[0] := 0;

Выдает ошибку External Sigsev, в дельфях только так и работало.
А использование:
Код: Выделить всё
  IntArray[0] := 0;

выдает ошибку компиляции о несовместимости типов.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Работа с указателями

Сообщение zub » 08.08.2013 10:26:19

>>IntArray = GetMem(100*SizeOf(integer));
IntArray = GetMem(SizeOf(TIntArray));
выделять память на элементы не надо, TIntArray это просто указатель

>>Выдает ошибку External Sigsev, в дельфях только так и работало.
т.к. гетмем не инициализирует выделяемую память (в ней мусор) ее нужно занулить руками, либо использовать связку new\dispose (в них работает инициализация выделенной памяти в соответствии с типом, но в делфях ямнип эти функции deprecated) вместо getmem\freemem

>>IntArray^[0] := 0;
>>IntArray[0] := 0;
это зависит от настроек проекта, в случае mode delphi разименовывать указатель необязательно т.е. оба варианта прокатят, в случае mode fpc работать будет только первый вариант (имхо он всяко предпочтительней)
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Работа с указателями

Сообщение Kemet » 08.08.2013 10:57:38

GetMem(IntArray, 100*SizeOf(integer))
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория

Re: Работа с указателями

Сообщение zub » 08.08.2013 11:03:22

Kemet
точно, но всетаки
Код: Выделить всё
GetMem(IntArray,SizeOf(TIntArray));
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Работа с указателями

Сообщение Kemet » 08.08.2013 11:07:30

zub писал(а):Kemet
точно, но всетаки
Код: Выделить всё
GetMem(IntArray,SizeOf(TIntArray));
Там динамический массив
TIntArray = array of integer
известен только размер элемента
Последний раз редактировалось Kemet 08.08.2013 11:10:18, всего редактировалось 1 раз.
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория

Re: Работа с указателями

Сообщение svk12 » 08.08.2013 11:08:43

В такой ситуации указатели не нужны:
Код: Выделить всё
type
  TIntArray = array if integer;
  PIntArray = ^ TIntArray;
var
//  IntArray: PIntArray;
  IntArray: TIntArray;
begin
//  IntArray = GetMem(100*SizeOf(integer));
  SetLength(IntArray,100);
  IntArray[0] := 0;
end
svk12
постоялец
 
Сообщения: 408
Зарегистрирован: 09.06.2008 18:42:47

Re: Работа с указателями

Сообщение zub » 08.08.2013 11:11:33

Kemet
И что? sizeof(TIntArray)=sizeof(pointer) и от колва элементов не зависит. переменная типа TIntArray по сути является указателем на сам массив

svk12
>>В такой ситуации указатели не нужны:
Всяко бывает, иногда нужны. Помня последнюю тему от SeZuka именно это ему и надо.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Работа с указателями

Сообщение svk12 » 08.08.2013 11:32:17

zub писал(а):>>В такой ситуации указатели не нужны:
Всяко бывает, иногда нужны. Помня последнюю тему от SeZuka именно это ему и надо.

Ну, если нужны именно указатели, то:
Код: Выделить всё
type
  TIntArray = array if integer;
  PIntArray = ^ TIntArray;
var
  IntArray: PIntArray;
begin
  New(IntArray);
  SetLength(IntArray^,100);
  IntArray[0]^ := 0;
end


Память под "тело" дин.массива в любом случае распределяется через SetLength().
svk12
постоялец
 
Сообщения: 408
Зарегистрирован: 09.06.2008 18:42:47

Re: Работа с указателями

Сообщение SeZuka » 08.08.2013 13:46:00

zub писал(а):Всяко бывает, иногда нужны. Помня последнюю тему от SeZuka именно это ему и надо.

Все "детство" работал с указателями, начиная с TP, потом на дельфях разных версий начиная с 3, везде все работало, в фпс постоянно на какие-то грабли наступаю.
Получается в фпс нужно вообще без указателей работать?

Добавлено спустя 24 минуты 34 секунды:
SeZuka писал(а):Память под "тело" дин.массива в любом случае распределяется через SetLength().

Реализация SetLength скрыта внутри фпс, непонятно где и что она выделяет, и влияет ли на нее смена менеджера памяти. И насколько помнится под переменные выделяется память в стеке, не страдает ли этим SetLength?
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Работа с указателями

Сообщение Mirage » 08.08.2013 14:56:25

Не вижу особых отличий при работе с указателями в FPC и Delphi. Разве что у FPC синтаксис построже, хотя в ранних версиях дельфей он тоже был построже.
А если есть возможность использовать дин. массивы, то лучше без указателей, да. И там и там.
SetLength на стеке ничего не выделяет и должна использовать текущий активный менеджер памяти. Хотя по поводу последнего рекомендую документацию читать чтобы точно убедиться.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Работа с указателями

Сообщение zub » 08.08.2013 15:01:14

>>Получается в фпс нужно вообще без указателей работать?
ХЗ. ИМХО. Всё можно написать без указателей, дело привычки, скорости выполнения и легкости поддержки.
Мое "детство" еще не кончилось)) указатели в полный рост, динмассивы, классы - не

>>Реализация SetLength скрыта внутри фпс, непонятно где и что она выделяет, и влияет ли на нее смена менеджера памяти
Выделяется память в куче. Выж не "конструируете" массив полностью руками, вы просто выделяете память под указатель на него, в дальнейшем работая с ним стандартными средствами
>>И насколько помнится под переменные выделяется память в стеке, не страдает ли этим SetLength?
Не страдает. Проблемы при выходе из зоны видимости будут только если копировать локальные переменные в глобальные не стандартными средствами, а например memcopy или хитро приводя типы обманывая "compiler magic" процедуры

Добавлено спустя 11 минут 23 секунды:
Mirage
>>Не вижу особых отличий при работе с указателями в FPC и Delphi
Да, с виду всё одинаково. Но, когда я сваливал с делфи2006 на фпц мне показалось что в фпц всё строже, ошибок он не прощает))
Многие неправильные вещи в делфи работали до поры до времени, всплывая при смене оси или компа или тупо по "фазе луны". В фпц такие моменты всплывают сразу.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Работа с указателями

Сообщение Лекс Айрин » 08.08.2013 15:33:17

zub писал(а):Многие неправильные вещи в делфи работали до поры до времени, всплывая при смене оси или компа или тупо по "фазе луны". В фпц такие моменты всплывают сразу.


Так это же хорошо!
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Работа с указателями

Сообщение SeZuka » 08.08.2013 17:38:44

Наткнулся тут на один пример:
Код: Выделить всё
{$R-}
uses crt;
const nmax=20;
type
  Tmas=^TTmas;{одна строка матрицы}
  TTmas=array[1..1] of integer;
  Tmatr=^TTmatr;{матрица-массив указателей на строки}
  TTmatr=array[1..1] of Tmas;
var
  a:Tmatr;
  n,m,i,j,k:integer;
  f:boolean;
begin
clrscr;
randomize;
repeat
write('Количество строк до ',nmax,' n=');
readln(n);
until n in [1..nmax];
repeat
write('Количество столбцов до ',nmax,' m=');
readln(m);
until m in [1..nmax];
getmem(a,sizeof(TTmatr)*n);{выделяем память под указатели на строки}
for i:=1 to m do
getmem(a^[i],sizeof(integer)*m);{для каждой строки память для хранения данных}
writeln ('Исходная матрица:');
for i:=1 to n do
begin
  for j:=1 to m do
   begin
    repeat
    a^[i]^[j]:=random(50)-25;
    until a^[i]^[j]<>0;{создаем матрицу без нолей}
    write(a^[i]^[j]:4);
   end;
  writeln;
end;
writeln;
for i:=1 to n do
begin
  j:=m;
  k:=0;
  while(j>=1)and(k=0) do
  if a^[i]^[j]<0 then k:=j
  else j:=j-1;
  if k<>0 then a^[i]^[j]:=0;{замена последнего отр. на 0}
  if k=m then f:=true; {если все}
end;
writeln('Замена последних отрицательных в строках на 0');
for i:=1 to n do
begin
  for j:=1 to m do
  write(a^[i]^[j]:4);
  writeln;
end;
for i:=1 to n do
freemem(a^[i],sizeof(integer)*m); {освобождаем память в обратном порядке, сначала удалим строки}
freemem(a,sizeof(TTmatr)*n); {потом указатели на них}
readln
end.

Работает без проблем, попробовал к своему коду применить, вместо
Код: Выделить всё
  TIntArray = array of integer;

написать:
Код: Выделить всё
  TIntArray = array [0..0] of integer;

Код: Выделить всё
  IntArray^[n] := m;

Все стало работать без ошибок External SIGSEV.
От сюда собственно и вопрос в чем глобальное отличие array of integer от array [0..0] of integer?
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Работа с указателями

Сообщение zub » 08.08.2013 18:25:34

>>От сюда собственно и вопрос в чем глобальное отличие array of integer от array [0..0] of integer?
Тут лучше какогонибудь учебника по делфи никто не объяснит. первый динамический, второй статический.
отличия те же что у дельфовой string и bp`шной string[255]
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Работа с указателями

Сообщение SeZuka » 09.08.2013 06:01:14

zub писал(а):Тут лучше какогонибудь учебника по делфи никто не объяснит. первый динамический, второй статический.
отличия те же что у дельфовой string и bp`шной string[255]

Я в том смысле что как их описание влияет на индексирование при работе с указателями? Ведь я не использую ни тот ни другой тип, память выделяю сам и мне нужен только доступ к ней по индексу, как в массиве.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru