Pascal. Delphi. Реалізація рядків типу PChar в пам’яті комп’ютера. Типи PAnsiChar, PWideChar

Реалізація рядків типу PChar в пам’яті комп’ютера. Типи PAnsiChar, PWideChar. Виділення пам’яті для рядків. Доступ за індексом


Зміст


Пошук на інших ресурсах:

1. Представлення ASCIIZ-рядків у мові Паскаль. Типи PChar, PAnsiChar, PWideChar

Крім стандартного представлення з допомогою типу String, у мові Паскаль рядки можуть бути представлені типами PChar, PAnsiChar та PWideChar. Ці типи визначають так звані ASCIIZ-рядки. Кожен ASCIIZ-рядок завершується спеціальним нульовим символом (нуль-термінатором), який позначається як ‘\0’ в C-орієнтованих мовах або #0 в Паскалі.

На рисунку 1 відображається представлення ASCIIZ-рядка у пам’яті комп’ютера.

Представлення ASCIIZ-рядка в пам’яті комп’ютера

Рисунок 1. Представлення ASCIIZ-рядка в пам’яті комп’ютера

Тип PChar описує покажчик на тип Char

type
  PChar = ^Char;

Модифікацією типу PChar є типи PAnsiChar та PWideChar, які є покажчиками відповідно на типи AnsiChar та WideChar. Більш детально про символьні типи у Free Pascal та Delphi описується тут.

 

2. Функції для роботи з типами PChar, PAnsiChar, PWideChar. Перелік

Для роботи з рядками типу PChar використовуються наступні функції:

  • StrCat, StrLCat – реалізує конкатенацію рядків;
  • StrComp, StrIComp, StrLComp, StrLIComp – порівнюють два рядки;
  • StrCopy, StrECopy, StrLCopy – копіюють значення одного рядка в інший;
  • StrDispose – знищує рядок та пам’ять, раніше виділену для нього;
  • StrEnd – повертає покажчик на символ, що завершує рядок;
  • StrLen – повертає довжину рядка;
  • StrLower – перетворює рядок в нижній регістр;
  • StrMove – переміщує один рядок на місце іншого рядка;
  • StrNew – виділяє пам’ять для нового рядка;
  • StrPas – конвертує рядок типу PChar в рядок типу String;
  • StrPCopy – копіює рядок типу String в рядок типу PChar;
  • StrPos – знаходить підрядок в рядку;
  • StrRScan, StrScan – знаходить позицію вказаного символа в рядку;
  • StrUpper – перетворює рядок в верхній регістр та повертає покажчик на нього.

 

3. Виділення пам’яті для рядків типу PAnsiChar, PWideChar. Функції AnsiStrAlloc, WideStrAlloc

Для того, щоб використовувати рядки типу PAnsiChar, PWideChar для них попередньо потрібно виділити необхідний фрагмент пам’яті. Для виділення пам’яті використовуються наступні функції

function AnsiStrAlloc(Size: Cardinal): PAnsiChar;
function WideStrAlloc(Size: Cardinal): PWideChar;

тут

  • Size – розмір рядка в символах. Для рядків типу PAnsiChar кожен символ займає 1 байт. Для рядків типу PWideChar кожен символ займає 2 байти (кодування Unicode).

Приклад.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  ps1 : PAnsiChar;
  ps2 : PWideChar;
  s : string;

begin
  // Функції AnsiStrAlloc, WideStrAlloc.
  // Демонструється ввід рядка з клавіатури консолі
  // та копіювання цього рядка в типи AnsiStrAlloc, WideStrAlloc

  // 1. Ввести рядок типу String з клавіатури
  Write('s = ');
  Readln(s);

  // 2. Функція AnsiStrAlloc
  // 2.1. Виділити пам'ять для рядка PAnsiChar,
  // розмір пам'яті рівний розміру рядка s
  ps1 := AnsiStrAlloc(Length(s));

  // 2.2. Скопіювати рядок s => ps1
  StrPCopy(ps1, s);

  // 2.3. Вивести ps1
  Writeln('ps1 = ', ps1);

  // 3. Функція WideStrAlloc
  // 3.1. Виділити пам'ять для рядка PWideChar
  ps2 := WideStrAlloc(Length(s));

  // 3.2. Копіювання s => ps2
  StrPCopy(ps2, s);

  // 3.3. Вивести ps2
  Writeln('ps2 = ', ps2);

  Readln;
end.

Результат

s = abcdef
ps1 = abcdef
ps2 = abcdef

 

4. Доступ до окремого символу рядка типу PChar, PAnsiChar, PWideChar. Операція доступу за індексом []

Для рядків типу PChar, PAnsiChar та PWideChar є можливість доступитись до заданого символу з допомогою операції індексування []. У загальному випадку доступ до елементу рядка виглядає так:

S[index]

тут

  • S – рядок типу PChar, PAnsiChar, PWideChar;
  • index – позиція символа, яка починається з 0.

Окремі символи рядків типу PChar, PAnsiChar, PWideChar можуть змінюватись. Це означає, що операція доступу за індексом [] може використовуватись як у виразі, так і в лівій частині оператора присвоювання.

Приклад.

У прикладі з допомогою доступу за індексом реалізується створення рядка типу PAnsiChar та PWideChar.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  ps1 : PAnsiChar;
  ps2 : PWideChar;
  i : Integer;
  s : string;

begin
  // Доступ за індексом []

  // 1. Створити рядок AnsiChar
  // 1.1. Виділити пам'ять для рядка
  ps1 := AnsiStrAlloc(10);

  // 1.2. Записати слово 'Hello!' в рядок ps1
  ps1[0] := 'H';
  ps1[1] := 'e';
  ps1[2] := 'l';
  ps1[3] := 'l';
  ps1[4] := 'o';
  ps1[5] := '!';
  ps1[6] := #0; // символ кінця рядка

  // 1.3. Вивести рядок в циклі
  Write('ps1 = ');
  for i := 0 to StrLen(ps1) do
    Write(ps1[i]);
  Writeln;

  // 2. Створити рядок WideChar
  // 2.1. Виділити пам'ять для рядка
  ps2 := WideStrAlloc(15);

  // 2.2. Записати слово 'BestProg' в рядок ps2
  ps2[0] := 'B';
  ps2[1] := 'e';
  ps2[2] := 's';
  ps2[3] := 't';
  ps2[4] := 'P';
  ps2[5] := 'r';
  ps2[6] := 'o';
  ps2[7] := 'g';
  ps2[8] := #0; // кінець рядка

  // 2.3. Вивести рядок
  Writeln('ps2 = ', StrPas(ps2));

  // 2.4. Додати до рядка '.net'
  ps2[8] := '.';
  ps2[9] := 'n';
  ps2[10] := 'e';
  ps2[11] := 't';
  ps2[12] := #0;

  // 2.5. Змінити 'B'->'b', 'P'->'p'
  ps2[0] := 'b';
  ps2[4] := 'p';

  // 2.6. Вивести ps2 на екран
  Writeln('ps2 = ', StrPas(ps2));

  Readln;
end.

Результат

ps1 = Hello!
ps2 = BestProg
ps2 = bestprog.net

 

5. Функція StrNew та процедура StrDispose. Виділення та звільнення пам’яті для рядків PAnsiChar та PWideChar

Для роботи з рядками типу PChar, PAnsiChar та PWideChar обов’язковими операціями є виділення та звільнення пам’яті в динамічній області. Для виконання цих операцій використовуються функції StrNew та StrDispose.

Функція StrNew створює новий рядок на основі існуючого та має наступні оголошення для типів PAnsiChar та PWideChar

function StrNew(const Str: PAnsiChar): PAnsiChar;
function StrNew(const Str: PWideChar): PWideChar;

тут

  • Str – константний рядок, для якого виділяється пам’ять.

Після закінчення роботи з рядком (в кінці програми, процедури чи деякої функції) потрібно звільнити пам’ять, виділену для цього рядка. Для цього призначена процедура StrDispose

procedure StrDispose(Str: PAnsiChar);
procedure StrDispose(Str: PWideChar);

тут

  • Str – рядок, для якого потрібно звільнити пам’ять.

Приклад.

У прикладі демонструється виділення пам’яті для рядка, який вводиться з клавіатури для консольного додатку. У цьому випадку довжина рядка на початку програми не відома і визначається у ході виконання програми.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  ps1 : PWideChar;
  s : string;

begin
  // Функція StrNew, процедура StrDispose.
  // Демонструється виділення пам'яті для рядка,
  // що введений з клавіатури. Довжина рядка на початку програми невідома.

  // 1. Створити вихідний рядок,
  // рядок вводиться з клавіатури в консольному додатку
  Write('s = ');
  Readln(s);

  // 2. Конвертувати s => ps1
  // 2.1. Виділити пам'ять для рядка ps1 функцією StrNew,
  // розмір пам'яті рівний довжині рядка s
  ps1 := StrNew(WideStrAlloc(Length(s)));

  // 2.2. Скопіювати рядок s => ps1
  StrPCopy(ps1, s);

  // 3. Вивести рядок ps1
  Writeln('ps1 = ', StrPas(ps1));

  // 4. Звільнити пам'ять, виділену для рядка ps1
  StrDispose(ps1);

  Readln;
end.

Результат.

s = BestProg
ps1 = BestProg

 

6. Функції StrPas та StrPCopy. Перетворення з типу String в тип PChar і навпаки

Корисними при використанні рядків у програмах є функції взаємного перетворення між форматами представлення рядкыв типу String та типу PChar. Для загального типу String використовуються його реалізації типів AnsiString та UnicodeString в яких символ займає відповідно 1 та 2 байти. Для узагальненого типу PChar так само існує різновиди, це типи PAnsiChar та PWideChar які враховують різні системи кодування в яких символи займають відповідно 1 та 2 байти.

Щоб перетворити з типів PAnsiChar та PWideChar у тип String потрібно використати функцію StrPas, яка має наступні оголошення

function StrPas(const Str: PAnsiChar): AnsiString;
function StrPas(const Str: PWideChar): UnicodeString;

тут

  • Str – рядок, який потрібно перетворити відповідно в тип AnsiString або UnicodeString.

Для перетворення з типу String в типи PAnsiChar та PWideChar використовується функція StrPCopy. Функція має наступні реалізації

function StrPCopy(Dest: PAnsiChar; const Source: AnsiString): PAnsiChar;
function StrPCopy(Dest: PWideChar; const Source: UnicodeString): PWideChar;

Приклад.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  ps1 : PAnsiChar;
  ps2 : PWideChar;
  s : string;

begin
  // Функції StrPas та StrPCopy

  // 1. Функція StrPas
  // 1.1. Сформувати рядок ps1 типу PAnsiChar
  ps1 := 'PAnsiChar';
  Writeln('ps1 = ', StrPas(ps1));

  // 1.2. Сформувати рядок ps2 типу PWideChar
  ps2 := StrNew('PWideChar');
  Writeln('ps2 = ', StrPas(ps2));

  // 1.3. Конвертувати PAnsiChar => String - функція StrPas
  s := StrPas(ps1);
  Writeln('StrPas(ps1) = ', s);

  // 1.4. Конвертувати PWideChar => String
  s := StrPas(ps2);
  Writeln('StrPas(ps2) = ', s);

  // 1.5. Звільнити ps2
  StrDispose(ps2);

  // 2. Функція StrPCopy
  // 2.1. Створити рядок s
  s := 'String';
  Writeln('s = ', s);

  // 2.2. Виділити фрагмент розміром 20 символів для типу PAnsiChar
  ps1 := AnsiStrAlloc(20);

  // 2.3. Скопіювати String => PAnsiChar
  StrPCopy(ps1, s);
  Writeln('StrPCopy(s) = ', StrPas(ps1));

  // 2.4. Виділити фрагмент для типу PWideChar
  ps2 := WideStrAlloc(20);

  // 2.5. Скопіювати String => PWideChar
  StrPCopy(ps2, s);
  Writeln('StrPCopy(s) = ', StrPas(ps2));

  // 2.6. Звільнити пам'ять, виділену для рядків ps1, ps2
  StrDispose(ps1);
  StrDispose(ps2);

  Readln;
end.

Результат

ps1 = PAnsiChar
ps2 = PWideChar
StrPas(ps1) = PAnsiChar
StrPas(ps2) = PWideChar
s = String
StrPCopy(s) = String
StrPCopy(s) = String

 


Споріднені теми