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

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

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

SeZuka
постоялец
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

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

Сообщение SeZuka »

Проясните как работать с указателями на массив.
Имеем:

Код: Выделить всё

type
  TIntArray = array if integer;
  PIntArray = ^ TIntArray;
var
  IntArray: PIntArray;
begin
  IntArray = GetMem(100*SizeOf(integer));

Как обращаться к элементам массива?

Код: Выделить всё

  IntArray^[0] := 0;

Выдает ошибку External Sigsev, в дельфях только так и работало.
А использование:

Код: Выделить всё

  IntArray[0] := 0;

выдает ошибку компиляции о несовместимости типов.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>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 работать будет только первый вариант (имхо он всяко предпочтительней)
Kemet
постоялец
Сообщения: 241
Зарегистрирован: 10.02.2010 18:28:32
Откуда: Временно оккупированная территория
Контактная информация:

Сообщение Kemet »

GetMem(IntArray, 100*SizeOf(integer))
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

Kemet
точно, но всетаки

Код: Выделить всё

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

Сообщение Kemet »

zub писал(а):Kemet
точно, но всетаки

Код: Выделить всё

 GetMem(IntArray,SizeOf(TIntArray));
Там динамический массив
TIntArray = array of integer
известен только размер элемента
Последний раз редактировалось Kemet 08.08.2013 11:10:18, всего редактировалось 1 раз.
svk12
постоялец
Сообщения: 411
Зарегистрирован: 09.06.2008 18:42:47

Сообщение svk12 »

В такой ситуации указатели не нужны:

Код: Выделить всё

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
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

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

svk12
>>В такой ситуации указатели не нужны:
Всяко бывает, иногда нужны. Помня последнюю тему от SeZuka именно это ему и надо.
svk12
постоялец
Сообщения: 411
Зарегистрирован: 09.06.2008 18:42:47

Сообщение svk12 »

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

Ну, если нужны именно указатели, то:

Код: Выделить всё

type
  TIntArray = array if integer;
  PIntArray = ^ TIntArray;
var
  IntArray: PIntArray;
begin
  New(IntArray);
  SetLength(IntArray^,100);
  IntArray[0]^ := 0;
end


Память под "тело" дин.массива в любом случае распределяется через SetLength().
SeZuka
постоялец
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Сообщение SeZuka »

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

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

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

Реализация SetLength скрыта внутри фпс, непонятно где и что она выделяет, и влияет ли на нее смена менеджера памяти. И насколько помнится под переменные выделяется память в стеке, не страдает ли этим SetLength?
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

Не вижу особых отличий при работе с указателями в FPC и Delphi. Разве что у FPC синтаксис построже, хотя в ранних версиях дельфей он тоже был построже.
А если есть возможность использовать дин. массивы, то лучше без указателей, да. И там и там.
SetLength на стеке ничего не выделяет и должна использовать текущий активный менеджер памяти. Хотя по поводу последнего рекомендую документацию читать чтобы точно убедиться.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

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

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

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

Сообщение Лекс Айрин »

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


Так это же хорошо!
SeZuka
постоялец
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Сообщение SeZuka »

Наткнулся тут на один пример:

Код: Выделить всё

{$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?
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>От сюда собственно и вопрос в чем глобальное отличие array of integer от array [0..0] of integer?
Тут лучше какогонибудь учебника по делфи никто не объяснит. первый динамический, второй статический.
отличия те же что у дельфовой string и bp`шной string[255]
SeZuka
постоялец
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Сообщение SeZuka »

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

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