Работа со строками через адрес (PString, Pointer)

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

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

Работа со строками через адрес (PString, Pointer)

Сообщение VirtUX » 12.09.2012 15:53:43

Как правильно выделить память для PString?
Например:
Есть связанный список:
Код: Выделить всё
type
PArr: ^TArr;
TArr = record
  Data: Pointer;
  Pred, Next: PArr;
end;

В этот список нужно добавить строку:
Код: Выделить всё
var
  pstr: pString;
  s: string;
  list: PArr;
begin
  s := 'ля-ля-ля';

  getmem(pstr, lenght(s) + ?);
  pstr^ := s;
  getmem(list, sizeof(TArr));
  list^.Data := Pointer(pstr);
end;

Что нужно вписать вместо ?, и приветствуется критика относительно "кошерности" кода :)
Последний раз редактировалось VirtUX 12.02.2014 17:09:21, всего редактировалось 1 раз.
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Выделение памяти для PString

Сообщение zub » 12.09.2012 16:34:03

Код: Выделить всё
getmem(pstr, sizeof(pstr));
pointer(pstr^)=nil;
pstr^:='blablabla'

PString - указатель на стринг, string по сути тоже указатель (на строку и заголовок), такчто lenght(s) в данном случае ненужен
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Выделение памяти для PString

Сообщение VirtUX » 12.09.2012 16:41:20

zub писал(а): lenght(s) в данном случае ненужен

Значит можно так:
Код: Выделить всё
s := 'ля-ля-ля';
  pstr^ := s;
  getmem(list, sizeof(TArr));
  list^.Data := Pointer(pstr);
?
Тогда вопрос: как освободится память в связанном списке после закрытия приложения?

Добавлено спустя 13 минут 55 секунд:
Для наглядности пример:
Код: Выделить всё
var
  pg: pointer;

procedure Any;
var
  p: pstring;
begin
  p^ := 'tra-ta-ta';
  pg := pointer(p);
end;

По завершении программы ОС корректно очистит память на которую ссылается pg?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Выделение памяти для PString

Сообщение zub » 12.09.2012 17:26:27

Код: Выделить всё
pg := pointer(p);

так нельзя, можно
Код: Выделить всё
pg := @p;

но нужно помнить что при изменении содержимого p изменится и содержимое pg^. а после окончания времени жизни p, pg станет невалидным

Зачем всё это?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Выделение памяти для PString

Сообщение VirtUX » 12.09.2012 17:58:21

Значит мой вопрос в силе.
zub писал(а):Зачем всё это?

Мне нужно хранить строки в списке. НО! Это могут быть и не строки, а к примеру булини. Я зарание не знаю, что туда попадет! Но список однозначно однородный. О том, что там хранится я знаю из доп параметров. Но да это все не важно :) Главное выделить память для строки, записать туда саму строку, и при необходимости очистить память для других данных (возможно не строк!)

Добавлено спустя 11 минут 52 секунды:
Может кто знает сколько байт в FPC для string выделяется под хранение длины строки? Т.к. я знаю, что максимальная длина строки не 256, а гораздо больше байт. В принципе ? = "этому количестве байт".
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Выделение памяти для PString

Сообщение zub » 12.09.2012 18:34:02

из astrings.inc (часть system)
Код: Выделить всё
Type
  PAnsiRec = ^TAnsiRec;
  TAnsiRec = Record
    CodePage    : TSystemCodePage;
    ElementSize : Word;
{$ifdef CPU64}   
    { align fields  }
   Dummy       : DWord;
{$endif CPU64}
    Ref         : SizeInt;
    Len         : SizeInt;
  end;
Const
  AnsiFirstOff = SizeOf(TAnsiRec);

это из 2.7.1, в 2.6 CodePage : TSystemCodePage; вроде небыло
но сюда лезти совсем не стоит, создание пстринг смотри во втором посте. под TAnsiRec и содержимое строки компилятор выделяет память сам
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Выделение памяти для PString

Сообщение Vapaamies » 12.09.2012 18:42:42

VirtUX писал(а):Главное выделить память для строки, записать туда саму строку, и при необходимости очистить память для других данных (возможно не строк!)

Если используются длинные строки, вообще ничего не нужно.
Код: Выделить всё
var
  Item: TArr;
begin
  New(Item);
  AnsiString(Item.Data) := 'тра-ля-ля'; // присваивание
  ...
  ...
  ...
  AnsiString(Item.Data) := '' // "освобождение", уменьшает счетчик ссылок
  Dispose(Item);
end;
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Выделение памяти для PString

Сообщение zub » 12.09.2012 18:52:40

Код: Выделить всё
AnsiString(Item.Data) := '' // "освобождение", уменьшает счетчик ссылок

если использовать new\dispose самому инициализировать\освобождать ненадо - это сделает компилятор
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Выделение памяти для PString

Сообщение Vapaamies » 12.09.2012 20:50:36

zub
Только если соответствующее поле описано как string, а у ТС оно Pointer.
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Выделение памяти для PString

Сообщение VirtUX » 12.09.2012 21:09:41

Vapaamies писал(а):AnsiString(Item.Data) := '' // "освобождение", уменьшает счетчик ссылок

И это действие гарантированно освободит всю память на которую будет указывать Item.Data, являясь по сути Pointer, а не AnsiString?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Выделение памяти для PString

Сообщение zub » 12.09.2012 21:18:52

>>Только если соответствующее поле описано как string, а у ТС оно Pointer.
незаметил. Тогда и инициализировать нужно за компилятор
Код: Выделить всё
  New(Item);
  pointer(Item.Data):=nil; //почистить возможный мусор
  AnsiString(Item.Data) := 'тра-ля-ля'; // присваивание


Добавлено спустя 3 минуты 29 секунд:
>>И это действие гарантированно освободит всю память на которую будет указывать Item.Data, являясь по сути Pointer, а не AnsiString?
Да.
Но тут подмена pointer`a string`ом, а не pstring`ом о котором шла речь в начале
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Выделение памяти для PString

Сообщение VirtUX » 13.09.2012 11:27:43

Оказалось, что решение уже было готово разработчиками FPC :)
function NewStr(S: string): PString;
и
procedure DisposeStr(S: PString);
Спасибо Vapaamies, что напомнил про New и Dispose - я уж и забыл про их существование :) Давно уж не пользовался статичным распределением памяти :)
P.S. По поводу длинных строк: String вполне подходит на роль хранения длинных строк. В FPC нет ограничения в 256 байт ;) Поэтому я и спрашивал про PString, а не AnsiString, WideString и пр. Еще ни разу у меня не возникла ситуация, когда простого string мне не хватало :) Т.о. я избавлен от различных привидений типа UTF8StringToAnsi и т.д. ИМХО!
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Выделение памяти для PString

Сообщение Vapaamies » 14.09.2012 03:11:41

zub писал(а):
Код: Выделить всё
  pointer(Item.Data):=nil; //почистить возможный мусор

На самом деле:
Код: Выделить всё
  Item.Data:=nil;

Потому как Item.Data и так уже Pointer. :)

VirtUX писал(а):Еще ни разу у меня не возникла ситуация, когда простого string мне не хватало :)

Видимо, стоит {$H+}, и string есть AnsiString. В наших примерах можно и приведение к string использовать, -- так даже лучше: компилятор заругается, если внезапно попадется ShortString.
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Выделение памяти для PString

Сообщение AlexVinS » 14.09.2012 21:08:52

А почему бы не сделать список дженериком и объявить специализации для каждого варианта?
Аватара пользователя
AlexVinS
новенький
 
Сообщения: 95
Зарегистрирован: 27.01.2009 01:18:01

Re: Выделение памяти для PString

Сообщение VirtUX » 12.02.2014 17:06:39

Чтоб не плодить похожие темы, спрошу тут.
На сколько корректен код; и освободится-ли память в куче, выделенная под хранение строки, после отработки процедуры?
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin

  String(u) := Edit2.Text;
  Edit1.Text:= IntToStr(Length(String(u)));

end;

P.S. Размер строки показывает правильно. Но не лезу-ли я в "чужую" кучу?...

Добавлено спустя 11 минут 5 секунд:
Re: Работа со строками через адрес (PString, Pointer)
Хм... Такой код тоже срабатывает без ошибок:
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin

  Integer(u) := 5789;
  Edit1.Text:= IntToStr(Integer(u));

end;
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

След.

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

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

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

Рейтинг@Mail.ru