Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Преобразование строк



Допустим, что у тебя есть строка типа String и ты хочешь её преобразовать в PChar. Для такого преобразования нужно написать требуемый тебе тип и в скобках указать свою строковую переменную: NewStr:=PChar(MyStr);. В этом примере переменная MuStr имеет тип String, а мы приводим её в вид PChar. Вот так происходит преобразования совместимых типов.

Вот такое преобразование строк мы будем делать очень часто при вызове WinAPI функций, потому что там большинство строк имеет именно PChar тип.

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

10.7 Указатели

ора познакомиться с указателями. Это очень удобная и сильная вещь, которой мы так же будем часто пользоваться. Уже в этой главе мы будем работать с указателями на структуры, которые расположим в динамической

памяти.

Но прежде чем что-то объяснять, я хочу показать тебе, зачем нужны указатели. Давай вспомним про процедуры, и я расскажу тебе, как происходит их вызов. Допустим, у тебя есть процедура с именем MyProc у которой есть два параметра: число и строка. Как происходит вызов такой процедуры, и как ей передаются эти параметры? Очень просто. Сначала параметры поднимаются в стек (напомню, что стек – это область памяти для хранения твоих временных/локальных переменных). Сначала заносится первый параметр, затем второй и после этого вызывается процедура. Прежде чем процедура начнёт своё выполнение, она достаёт эти параметры из стека в обратном порядке.

Теперь вспомним о наших параметрах. Первый – это число, которое будет занимать два байта. Когда мы подымем его в стек, то оно займёт там свои положенные два байта. Второй параметр – строка. Каждый символ строки – это отдельный байт. Допустим, что наша строка состоит из 10 символов, значит для передачи такой строки в процедуру, в стеке понадобиться 10 байт плюс один байт для указания конца строки или размерности (это зависит от типа строки). Всего для передачи в процедуру нам понадобиться в стеке как минимум 12 байт. Это не так уж и много, поэтому такое можно себе позволить.

А теперь представь, что строка, которую надо передать в процедуру, состоит из 1000 символов. Вот тут нам понадобиться в стеке уже около килобайта. При нынешних размерах памяти на это уже никто не обращает внимания, но народ забывает про то, что такая строка сначала копируется в память стека, а потом достаётся оттудова. Такое копирование большого размера памяти отнимает достаточно много времени и твоя программа тратит лишнее время на бессмысленное копирование большой строки.

Выход из сложившейся ситуации достаточно прост – можно не передавать строку, а только передать указатель на область памяти, где находиться эта строка. Любой указатель занимает всего четыре байта, а это уже существенная экономия. Мы просто передаём два байта указывающих на длинную строку, а процедура достаёт эти два байта и уже знает, где можно взять строку, когда она понадобиться.

Указатель в Delphi объявляется как Pointer. Например, давай объявим переменную p типа указатель:

var p:Pointer

Для того, чтобы получить адрес переменной или объекта, необходимо перед его именем поставить знак @. Например, у тебя есть строка Str и чтобы присвоить её адрес в указатель p, надо выполнить следующее: p:=@Str;. Теперь в указателе находиться адрес строки. Если ты будешь напрямую читать указатель, то увидишь адрес, а для того чтобы увидеть содержащиеся по этому адресу данные, надо разыменовывать указатель. Для этого надо написать p^. Итак, мы пришли к следующему:

p:=@Str – получить адрес строки.

p – указатель на строку.

p^ -данные, содержащиеся по адресу указанному в p.

Давай создадим маленькое приложение, которое будет работать с указателями. Для этого создай форму приблизительно следующего содержания:

По нажатию кнопки «Работа со ссылками» напиши следующее:

var p:Pointer Str:String;

begin p:=@Str; // Присваиваю указателю ссылку на строку Str:='Привет мой друг'; // Изменяю значение строки Edit1.Text:=String(p^); // Вывожу текст

End;

В этом примере, в первой строке я присваиваю указателю p ссылку на строку Str. После этого я меняю содержимое строки. И в последней строчке я вывожу содержащийся по адресу p текст. Для этого приходиться явно указывать, что по адресу p находиться именно строка String(p^). Это необходимо, потому что данные, расположенные по определённому адресу могут иметь совершенно любой тип. Как видишь, жёсткое указание типа похоже на преобразование типов, поэтому никаких проблем с этим не должно возникнуть.

Заметь, что я изменяю строку после присваивания адреса строки в переменную указатель, и изменённые данные всё равно будут отражены в указателе. Это потому что указатель всегда показывает на начало строки, и если мы её изменим, указателю будет всё равно, потому что новые данные будут расположены по тому же адресу, и p будет указывать на новую строку.

На компакт диске, в директории \Примеры\Глава 10\Pointers ты можеш ь увидеть приме р это й программы.

Мы уже не раз использовали указатели, просто не углублялись в их изучение. Каждая переменная типа объекта – это тоже указатель на объект. Просто его использование выполнено так, чтобы не смущать тебя адресацией и разыменовыванием.

Любой переменной указателю можно присвоить нулевое значение, только это не 0, а nil, например p:=nil;. Когда ты присваиваешь нулевое значение, то ты как бы уничтожаешь ссылку. Точно так же, если ты переменной объекту присвоишь нулевое значение, ты его уничтожишь, и объект больше не будет существовать.

А что если у тебя две переменные указывают на один и тот же адрес данных? Неужели при уничтожении одного из них данные уничтожаться и вторая переменная будет указывать на несуществующие данные? Нет, объект будет уничтожен только после того, как все указатели на него будут уничтожены.

10.8 Структуры, записи

ейчас я хочу тебя познакомить поближе со структурами и записями. Точнее сказать, оба понятия означают одно и тоже. Просто в С++ принято говорить «структура», а в Delphi говорят «запись». Так как я знаю оба языка, я больше

привык к понятию «структура», потому что оно больше отражает смысл этого понятия. Тебе нужно только привыкнуть, что структура – это та же запись.

Я уже упоминал о структурах немного раньше. Они похожи на объекты, только не имеют методом и событий, а только свойства.

Для объявления структуры используется следующий вид:

Имя структуры = record Свойство1: Тип свойства1; Свойство2: Тип свойства2; ….

End;

Давай опишем структуру, в которой будут храниться параметры окна:

WindowsSize = record Left:Integer; Top:Integer; Width:Integer; Height:Integer;

End;

Я назвал новую структуру как WindowSize и объявил внутри четыре свойства: Left, Top, Width, Height.

Свойства я объявлял каждое в отдельности, хотя в данном случае все они имеют один тип и их можно просто перечислить через запятую и указать, что все они имеют целый тип:

WindowsSize = record

Left, Top, Width, Height:Integer; end;

Точно так же можно объявлять и переменные в разделе var, когда несколько переменных имеют один и тот же тип.

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

var ws: WindowSize;

Структуры – это простые сгруппированные наборы свойств, которые по умолчанию не требуют выделения памяти. Они создаются локально в стеке. Напоминаю, что стек – область памяти для хранения локальных/временный переменных. Так же следует напомнить чем отличаются локальные переменные от глобальных:

Локальные переменные – объявляются и создаются при входе в процедуру и уничтожаются при выходе. Глобальные переменные – создаются при запуске программы и уничтожаются при выходе из неё. Это значит, что глобальные переменные существуют на протяжении всего времени выполнения программы. Локальные переменные существуют, только когда выполняется код процедуры. После первого выполнения процедуры локальные переменные уничтожаются и при следующем вызове создаются снова с нулевым значением. Поэтому, если надо сохранить значение переменной после выхода из процедуры, её следует объявить как глобальную.

Итак, переменная объявлена. Инициализация и уничтожение не требуется, поэтому можно сразу же её использовать. Для доступа к переменным структуры нужно написать имя структуры и через точку указать тот параметр, который тебя интересует. Например, для доступа к параметру Left необходимо написать: ws.Left.

Давай напишем пример, который будет после закрытия программы сохранять текущие значения позиции окна в структуре, а потом эту структуру будем записывать в файл. Для записи будет использоваться простой бинарный файл, значит, воспользуемся объектом TFileStream.

Итак, создай новое приложение. В разделе Type опиши нашу структуру:

type WindowsSize = record Left, Top, Width, Height:Integer; end;

TForm1 = class(TForm)
private
public
end;

Теперь создай обработчик события OnClose для формы. Здесь мы заполним структуру значениями позиции окна и сохраним в бинарный файл:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

var ws:WindowsSize; f:TFileStream; Str:String;

begin ws.Left:=Left; // Заполняем левую позицию ws.Top:=Top; // Заполняем правую позицию ws.Width:=Width; // Заполняем ширину окна ws.Height:=Height; // Заполняем высоту окна

f:=TFileStream.Create('size.dat', fmCreate); // Создаю файл Size.dat
f.Write(ws, sizeof(ws)); // Записываю структуру
f.Free; // Закрываю файл

End;

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

Ну а теперь разберёмся с чтением из файла, которое происходит подобным образом:

procedure TForm1.FormShow(Sender: TObject);

var ws:WindowsSize; fs:TFileStream;

begin if FileExists('size.dat') then // Если файл Size.dat существует, то

begin
fs:=TFileStream.Create('size.dat', fmOpenRead); // Открываю файл Size.dat
fs.Read(ws, sizeof(ws)); // Читаю содержимое структуры
fs.Free; // Закрываю файл

// Дальше я устанавливаю сохранённые размеры и позицию окна на родину Left:=ws.Left; Top:=ws.Top; Width:=ws.Width; Height:=ws.Height;





Дата публикования: 2014-11-04; Прочитано: 480 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.009 с)...