Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];

Вниз

Проблема с типом PAnsiChar.   Найти похожие ветки 

 
Demi   (2004-04-23 23:35) [0]

Не получается преобразовать String в PAnsiChar.

var per1, per2: PAnsiChar;
begin
per1 := ‘c:\ddd.bmp’;
per2 := ‘d:\ddd.bmp’;
copyfile(per1, Per2, true);
end;   //Всё вроде в порядке;

Но если пытаюсь вот так, то не получается, а очень надо.

var per1, per2: pansiChar;
begin
per1 := Edit1.Text       //И всё, приехал;
……………………………..
……………………………..
end;

Подскажите пожалуйста как эту проблему исправить? Спасибо.


 
Demi   (2004-04-23 23:35) [0]

Не получается преобразовать String в PAnsiChar.

var per1, per2: PAnsiChar;
begin
per1 := ‘c:\ddd.bmp’;
per2 := ‘d:\ddd.bmp’;
copyfile(per1, Per2, true);
end;   //Всё вроде в порядке;

Но если пытаюсь вот так, то не получается, а очень надо.

var per1, per2: pansiChar;
begin
per1 := Edit1.Text       //И всё, приехал;
……………………………..
……………………………..
end;

Подскажите пожалуйста как эту проблему исправить? Спасибо.


 
evvcom ©   (2004-04-23 23:58) [1]

per1 := PAnsiChar(Edit1.Text);
или
per1 := PChar(Edit1.Text);


 
evvcom ©   (2004-04-23 23:58) [1]

per1 := PAnsiChar(Edit1.Text);
или
per1 := PChar(Edit1.Text);


 
Demi   (2004-04-24 00:00) [2]

Большое спасибо ты меня выручил!!!!


 
Demi   (2004-04-24 00:00) [2]

Большое спасибо ты меня выручил!!!!


 
Piter ©   (2004-04-24 14:05) [3]

В данной мини-статье предлагаю рассмотреть типы данных PChar и String.
Оба этих типа предназначены для хранения произвольного текста, только производят они это хранение по разному.
Замечу, что текст - это последовательный набор символов в памяти. Это верно для всех строковых типов.

PChar
Тип PChar  устроен очень просто. В памяти компьютера хранится массив символов, а сам PChar указывает на первый символ. Этот символ и последующие и будут составлять строку.
Но возникает вопрос - а где конец строки? На начало указыват сам PChar, а вот конец строки определяется по завершающему символу. Для PChar он равен #0  или, что тоже самое, байту $00.
Завершаюший символ имеет код #0, но он не имеет текстового представления. То есть, он не может встретиться в тексте, это не цифра, не буква и не знак препинания. Поэтому его и выбрали в качестве завершающего символа, чтобы встретив в тексте можно было сказать , что это конец строки, а не случайно попавшийся байт. И не надо путать завершающий код с кодом перевода строчки, имеющего в windows системах значение #13#10 (то есть, два байта, возвещающие о том, что дальше текст идет с новой строчки).
Получается, что PChar - это строка от символа на который как раз и указывает PChar до завершающего символа.

Перед тем как использовать PChar нужно выделить память под него. Причем, если вы хотите чтобы можно было записать 255 символов, то нужно выделить 256 байт памяти - ведь нужен еще один байт на завершащий символ.

Приведем пример вызова WinApi функции GetWindowsDirectory, которая позволяет узнать путь к директории Windows. Покажем только принципиальную часть, практически настоятельно рекомендуется использовать тип AnsiString (который будет рассмотрен далее) для работы со строками. В реальных задачах не имеет смысла работать с PChar.
Итак, пример:

var
 P:PChar;
begin
 GetMem(P,MAX_PATH+1); //выделяем память под PChar
 GetWindowsDirectory(P,MAX_PATH); // вызываем API функцию. Причем, даем понять, что
 // готовы записать в наш буфер только MAX_PATH символов, хотя выделили MAX_PATH+1 байт
...


Все достаточно просто. Только после использования переменной P не забудьте очистить память командой FreeMem(P) во избежание утечек памяти.

Есть некоторые нюансы, которые иногда вводят в заблуждение неопытных программистов. Рассмотрим такой фрагмент программы:

var
 P:PChar;
begin
 P:="Hello, world";


Строчка P:="Hello, world";  на самом деле не имеет смысла. Ведь PChar - это указатель на первый символ строки. Как любой указатель в 32-ух битных системах, он также является 32-ух битным и никак не может равняться "Hello, World". Но компилятор Delphi для упрощения нашей с вами жизни все понимает правильно.
Некоторые думают, что при исполнении данной команды выделяется память, достаточная для размещения строчки "Hello, world" и потом эта строчка копируется в выделенную память. Но все совсем не так! Зачем что-то куда-то копировать? Понятное дело, что строка "Hello, World" при компиляции  будет "зашита" где-то в exe"шнике. При исполнении этого exe файла строчка также будет спроецирована в адресное пространство процесса (в сегмент данных) и будет иметь вполне определенный и постоянный адрес на всем протяжении исполнения программы. Так можно просто присвоить P адрес этой строчки? Что компилятор и сделает. Delphi строчку P:="Hello, world"; выполнит таким образом: просто присвоит P адрес буквы "H" в адресном пространстве процесса. Этот адрес будет известен еще на стадии компиляции.
При этом никакого выделения памяти не будет! И если с P вы потом делать ничего не будете - то и память освобождать не надо!
Код:

var
 P:PChar;
begin
 P:="Hello, world";
 FreeMem(P);
end;


Некорректный. Вы пытаетесь освобождать память, которую никто не выделял.

Ну и напоследок. Если даны переменные P1 и P2 типа PChar, то их присвоение:
P1:=P2
приведет к копированию адреса на который указывает P2 в P1. То есть, обе переменных будут ссылаться на одну и ту же строчку в памяти (на одну и ту же область памяти).

PChar не лишен недостатков. Допустим, вам надо работать с произвольным набором байтов, а не с текстом. Тут PChar не подходит, потому что в таком наборе случайно может встретиться символ #0, который будет принят за окончания строки, хотя это и не так.

String
Сначала определимся, что String - это тип, зависящий от директив компилятора. При директиве {$H+}, которая установлена по умолчанию, String интерпретируется как AnsiString, если {$H-} - то как ShortString.

Подумаем - как побороть недостаток PChar"а? Выход прост - пусть строка имеет такой формат:
<количество_символов> <сама_строка>.
Именно такой формат имеет ShortString. Первый байт этой строки указывает количество последующих символов. Таким образом, можно хранить любые данные, компьютер не остановится, увидев завершающий символ, так как конец строки определяется по другому признаку. Если длина 15 - то он будет обрабатывать именно 15 символов (байт), независимо от того, что в них хранится. ShortString не имеет завершающего символа в конце, поэтому не совместим с WinApi, где нужно передавать строки именно с завершающим символом.

Недостаток типа ShortString заключается в его названии :) Он достаточно короткий. Так как на длину строки отводится 1 байт, то она не может принимать значение более 255, а значит ShortString не может хранить более 255 символов.

Плавно переходим к типу AnsiString (по умолчанию этому типу и равен String). Тут все достаточно сложно, данная строка хранит размер выделенной памяти, счетчик ссылок, число символов. Мы не будет рассматривать побайтово его структуру в памяти. В любом случае, внутренняя реализация скрыта от программиста и использовать тип AnsiString очень удобно.
На размер строки отводится 4 байта, соответственно, AnsiString может хранить огромное количество символов (порядка 2 Гб), что покроет с лихвой любые нужды.


 
Piter ©   (2004-04-24 14:05) [3]

В данной мини-статье предлагаю рассмотреть типы данных PChar и String.
Оба этих типа предназначены для хранения произвольного текста, только производят они это хранение по разному.
Замечу, что текст - это последовательный набор символов в памяти. Это верно для всех строковых типов.

PChar
Тип PChar  устроен очень просто. В памяти компьютера хранится массив символов, а сам PChar указывает на первый символ. Этот символ и последующие и будут составлять строку.
Но возникает вопрос - а где конец строки? На начало указыват сам PChar, а вот конец строки определяется по завершающему символу. Для PChar он равен #0  или, что тоже самое, байту $00.
Завершаюший символ имеет код #0, но он не имеет текстового представления. То есть, он не может встретиться в тексте, это не цифра, не буква и не знак препинания. Поэтому его и выбрали в качестве завершающего символа, чтобы встретив в тексте можно было сказать , что это конец строки, а не случайно попавшийся байт. И не надо путать завершающий код с кодом перевода строчки, имеющего в windows системах значение #13#10 (то есть, два байта, возвещающие о том, что дальше текст идет с новой строчки).
Получается, что PChar - это строка от символа на который как раз и указывает PChar до завершающего символа.

Перед тем как использовать PChar нужно выделить память под него. Причем, если вы хотите чтобы можно было записать 255 символов, то нужно выделить 256 байт памяти - ведь нужен еще один байт на завершащий символ.

Приведем пример вызова WinApi функции GetWindowsDirectory, которая позволяет узнать путь к директории Windows. Покажем только принципиальную часть, практически настоятельно рекомендуется использовать тип AnsiString (который будет рассмотрен далее) для работы со строками. В реальных задачах не имеет смысла работать с PChar.
Итак, пример:

var
 P:PChar;
begin
 GetMem(P,MAX_PATH+1); //выделяем память под PChar
 GetWindowsDirectory(P,MAX_PATH); // вызываем API функцию. Причем, даем понять, что
 // готовы записать в наш буфер только MAX_PATH символов, хотя выделили MAX_PATH+1 байт
...


Все достаточно просто. Только после использования переменной P не забудьте очистить память командой FreeMem(P) во избежание утечек памяти.

Есть некоторые нюансы, которые иногда вводят в заблуждение неопытных программистов. Рассмотрим такой фрагмент программы:

var
 P:PChar;
begin
 P:="Hello, world";


Строчка P:="Hello, world";  на самом деле не имеет смысла. Ведь PChar - это указатель на первый символ строки. Как любой указатель в 32-ух битных системах, он также является 32-ух битным и никак не может равняться "Hello, World". Но компилятор Delphi для упрощения нашей с вами жизни все понимает правильно.
Некоторые думают, что при исполнении данной команды выделяется память, достаточная для размещения строчки "Hello, world" и потом эта строчка копируется в выделенную память. Но все совсем не так! Зачем что-то куда-то копировать? Понятное дело, что строка "Hello, World" при компиляции  будет "зашита" где-то в exe"шнике. При исполнении этого exe файла строчка также будет спроецирована в адресное пространство процесса (в сегмент данных) и будет иметь вполне определенный и постоянный адрес на всем протяжении исполнения программы. Так можно просто присвоить P адрес этой строчки? Что компилятор и сделает. Delphi строчку P:="Hello, world"; выполнит таким образом: просто присвоит P адрес буквы "H" в адресном пространстве процесса. Этот адрес будет известен еще на стадии компиляции.
При этом никакого выделения памяти не будет! И если с P вы потом делать ничего не будете - то и память освобождать не надо!
Код:

var
 P:PChar;
begin
 P:="Hello, world";
 FreeMem(P);
end;


Некорректный. Вы пытаетесь освобождать память, которую никто не выделял.

Ну и напоследок. Если даны переменные P1 и P2 типа PChar, то их присвоение:
P1:=P2
приведет к копированию адреса на который указывает P2 в P1. То есть, обе переменных будут ссылаться на одну и ту же строчку в памяти (на одну и ту же область памяти).

PChar не лишен недостатков. Допустим, вам надо работать с произвольным набором байтов, а не с текстом. Тут PChar не подходит, потому что в таком наборе случайно может встретиться символ #0, который будет принят за окончания строки, хотя это и не так.

String
Сначала определимся, что String - это тип, зависящий от директив компилятора. При директиве {$H+}, которая установлена по умолчанию, String интерпретируется как AnsiString, если {$H-} - то как ShortString.

Подумаем - как побороть недостаток PChar"а? Выход прост - пусть строка имеет такой формат:
<количество_символов> <сама_строка>.
Именно такой формат имеет ShortString. Первый байт этой строки указывает количество последующих символов. Таким образом, можно хранить любые данные, компьютер не остановится, увидев завершающий символ, так как конец строки определяется по другому признаку. Если длина 15 - то он будет обрабатывать именно 15 символов (байт), независимо от того, что в них хранится. ShortString не имеет завершающего символа в конце, поэтому не совместим с WinApi, где нужно передавать строки именно с завершающим символом.

Недостаток типа ShortString заключается в его названии :) Он достаточно короткий. Так как на длину строки отводится 1 байт, то она не может принимать значение более 255, а значит ShortString не может хранить более 255 символов.

Плавно переходим к типу AnsiString (по умолчанию этому типу и равен String). Тут все достаточно сложно, данная строка хранит размер выделенной памяти, счетчик ссылок, число символов. Мы не будет рассматривать побайтово его структуру в памяти. В любом случае, внутренняя реализация скрыта от программиста и использовать тип AnsiString очень удобно.
На размер строки отводится 4 байта, соответственно, AnsiString может хранить огромное количество символов (порядка 2 Гб), что покроет с лихвой любые нужды.


 
Piter ©   (2004-04-24 14:06) [4]

К тому же, AnsiString совместим с типами с завершающими символами в конце. Это означает, что его можно использовать для вызова функций WinApi.
Также стоит упомянуть, что ShortString статический тип, то есть под него однажды выделяют место в памяти и он так и остается там по одному адресу.
AnsiString же тип динамический, эта строка может менять свою длину и "перемещаться" по памяти в поисках наилучшего места для размещения. То есть, AnsiString может менять свой адрес в памяти при изменении строки.

Преобразования типов
Итак, как преобразовать тип PChar к AnsiString и наоборот?

AnsiString->PChar
Рассмотрим на примере вызовов функций WinApi, которые принимают параметры типа PChar. А мы работаем в Дельфи и хотим использовать String (точнее AnsiString).

Рассмотрим вызов функции:
function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;
которая вызывает на экране появление бокса с сообщением.

Параметры lpText и lpCaption являются PChar.
Указываем компилятору явно преобразовать AnsiString в Pchar:

procedure TForm1.Button1Click(Sender: TObject);
var s1, s2:string;
begin
 s1:="text";
 s2:="caption";
 MessageBox(0,PChar(s1),PChar(s2),0);
end;


Вот и все!

Тут все ясно. Но что делать, когда нужно передать PChar для того, чтобы система заполнила его каким-нибудь значением?

Рассмотрим вызов уже знакомой функции
GetWindowsDirectory(lpBuffer: PChar; uSize: UINT): UINT;
которая записывает путь к директории Windows в передаваемую переменную lpBuffer.

procedure TForm1.Button1Click(Sender: TObject);
var
 s:string;
begin
 setlength(s,MAX_PATH);
 GetWindowsDirectory(PChar(s),MAX_PATH);
 ...


В общем, это аналог вызова GetWindowsDirectory с PChar"ом, который мы рассматривали ранее.
Все тоже самое, НЕ ЗАБЫВАЕМ ВЫДЕЛИТЬ ПАМЯТЬ для переменной S перед использованием:
setlength(s,MAX_PATH)
В отличии от GetMem для выделения памяти PChar, для AnsiString применяется SetLength (причем, не надо учитывать завершающий символ).

После вызова GetWindowsDirectory в строке S также будет находится MAX_PATH символов (сколько выделили - столько и есть, а выделили по максимуму - откуда знать сколько памяти занимает путь к директории с Windows). Причем, скорее всего большинство их них пробелы, которые вовсе не нужны. Поэтому, перед использованием такой строки отрежем ненужные символы. Так как GetWindowsDirectory возвращает количество записанных символов, то код очевиден:

procedure TForm1.Button1Click(Sender: TObject);
var
 s:string;
 Length: integer;
begin
 setlength(s,MAX_PATH);
 Length := GetWindowsDirectory(PChar(s),MAX_PATH);
 setlength(s,Length); // укорачиваем строчу, выделяя ей меньше памяти
 // при этом все символы после позиции Length будут отрезаны
 ...


Ну а теперь рассмотрим сложный вариант.


var p:PChar;
...
p:=PChar(s); // где-то есть переменная s и в ней хранится некая строка


При этом p начинает указывать на ту же область памяти, что и s. И все будет замечательно, пока с s ничего не происходит. Но вот например:

var p:PChar;
   s:string;
begin
 setlength(s,MAX_PATH);
 setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

 p:=PChar(s);
 s:=s+"SomeText";
 ...


Итак, строчками
setlength(s,MAX_PATH);
setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

в s заносится путь к директории windows. В памяти таким образом появляется некая строка, допустим "c:\windows", которой и равна s.
После чего идет
p:=PChar(s);
при этом p начинает указывать на ту же область памяти, где находится строка "c:\windows".
Потом s присваивается другое значение
s:=s+"SomeText";
А точнее к s должно быть прибавлено "SomeText". При этом менеджер памяти анализирует ситуацию, можно ли приписать данный текст прямо в ту же область памяти. Если память после "c:\windows" не занята, то он приписывает нужное количество символов. При этом S будет указывать по прежнему на тот же адрес в памяти, только увеличится счетчик символов. Соответстенно, и с P, указывающим туда же, будет все нормально. И после завершения кода P будет указывать на строчку "c:\windowsSomeText".
Это первый вариант развития событий.

Но если невозможно подряд разместить все новые символы, то менеджер памяти будет искать "дырку", свободную для размещения всех символов. При этом память, где хранится текущее "c:\windows" будет объявлена свободной, резервируется место для новой строки в другом месте, туда записывается значение "c:\windowsSomeText" и S начинает указывать на новый участок памяти, где хранится новое значение строки. А P по прежнему указывает на старый участок памяти! Скорее всего, там будет продолжать хранится строчка "c:\windows", потому как память никто не зачищал, но эта память является уже свободной. И в случае чего, данное место будет зарезервировано под иные нужды и там разместятся произвольные данные, в результате P будет указывать на черт знает что.
Для демонстрации можно выполнить такой пример:

var p:PChar;
   s:string;
   s2:string;
begin
 setlength(s,MAX_PATH);
 setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

 p:=PChar(s);
 setlength(s2,1);
 s:=s+"SomeText";
end;


Тоже самое, но добавилась строчка setlength(s2,1);
Рассмотрим еще раз:
p:=PChar(s)
Что s, что P указывают на одну и ту же область памяти.
А потом
setlength(s2,1);
если ничего неожиданного не случится, то менеджер памяти Дельфи выделит под переменную s2 место сразу после s.


 
Piter ©   (2004-04-24 14:06) [4]

К тому же, AnsiString совместим с типами с завершающими символами в конце. Это означает, что его можно использовать для вызова функций WinApi.
Также стоит упомянуть, что ShortString статический тип, то есть под него однажды выделяют место в памяти и он так и остается там по одному адресу.
AnsiString же тип динамический, эта строка может менять свою длину и "перемещаться" по памяти в поисках наилучшего места для размещения. То есть, AnsiString может менять свой адрес в памяти при изменении строки.

Преобразования типов
Итак, как преобразовать тип PChar к AnsiString и наоборот?

AnsiString->PChar
Рассмотрим на примере вызовов функций WinApi, которые принимают параметры типа PChar. А мы работаем в Дельфи и хотим использовать String (точнее AnsiString).

Рассмотрим вызов функции:
function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;
которая вызывает на экране появление бокса с сообщением.

Параметры lpText и lpCaption являются PChar.
Указываем компилятору явно преобразовать AnsiString в Pchar:

procedure TForm1.Button1Click(Sender: TObject);
var s1, s2:string;
begin
 s1:="text";
 s2:="caption";
 MessageBox(0,PChar(s1),PChar(s2),0);
end;


Вот и все!

Тут все ясно. Но что делать, когда нужно передать PChar для того, чтобы система заполнила его каким-нибудь значением?

Рассмотрим вызов уже знакомой функции
GetWindowsDirectory(lpBuffer: PChar; uSize: UINT): UINT;
которая записывает путь к директории Windows в передаваемую переменную lpBuffer.

procedure TForm1.Button1Click(Sender: TObject);
var
 s:string;
begin
 setlength(s,MAX_PATH);
 GetWindowsDirectory(PChar(s),MAX_PATH);
 ...


В общем, это аналог вызова GetWindowsDirectory с PChar"ом, который мы рассматривали ранее.
Все тоже самое, НЕ ЗАБЫВАЕМ ВЫДЕЛИТЬ ПАМЯТЬ для переменной S перед использованием:
setlength(s,MAX_PATH)
В отличии от GetMem для выделения памяти PChar, для AnsiString применяется SetLength (причем, не надо учитывать завершающий символ).

После вызова GetWindowsDirectory в строке S также будет находится MAX_PATH символов (сколько выделили - столько и есть, а выделили по максимуму - откуда знать сколько памяти занимает путь к директории с Windows). Причем, скорее всего большинство их них пробелы, которые вовсе не нужны. Поэтому, перед использованием такой строки отрежем ненужные символы. Так как GetWindowsDirectory возвращает количество записанных символов, то код очевиден:

procedure TForm1.Button1Click(Sender: TObject);
var
 s:string;
 Length: integer;
begin
 setlength(s,MAX_PATH);
 Length := GetWindowsDirectory(PChar(s),MAX_PATH);
 setlength(s,Length); // укорачиваем строчу, выделяя ей меньше памяти
 // при этом все символы после позиции Length будут отрезаны
 ...


Ну а теперь рассмотрим сложный вариант.


var p:PChar;
...
p:=PChar(s); // где-то есть переменная s и в ней хранится некая строка


При этом p начинает указывать на ту же область памяти, что и s. И все будет замечательно, пока с s ничего не происходит. Но вот например:

var p:PChar;
   s:string;
begin
 setlength(s,MAX_PATH);
 setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

 p:=PChar(s);
 s:=s+"SomeText";
 ...


Итак, строчками
setlength(s,MAX_PATH);
setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

в s заносится путь к директории windows. В памяти таким образом появляется некая строка, допустим "c:\windows", которой и равна s.
После чего идет
p:=PChar(s);
при этом p начинает указывать на ту же область памяти, где находится строка "c:\windows".
Потом s присваивается другое значение
s:=s+"SomeText";
А точнее к s должно быть прибавлено "SomeText". При этом менеджер памяти анализирует ситуацию, можно ли приписать данный текст прямо в ту же область памяти. Если память после "c:\windows" не занята, то он приписывает нужное количество символов. При этом S будет указывать по прежнему на тот же адрес в памяти, только увеличится счетчик символов. Соответстенно, и с P, указывающим туда же, будет все нормально. И после завершения кода P будет указывать на строчку "c:\windowsSomeText".
Это первый вариант развития событий.

Но если невозможно подряд разместить все новые символы, то менеджер памяти будет искать "дырку", свободную для размещения всех символов. При этом память, где хранится текущее "c:\windows" будет объявлена свободной, резервируется место для новой строки в другом месте, туда записывается значение "c:\windowsSomeText" и S начинает указывать на новый участок памяти, где хранится новое значение строки. А P по прежнему указывает на старый участок памяти! Скорее всего, там будет продолжать хранится строчка "c:\windows", потому как память никто не зачищал, но эта память является уже свободной. И в случае чего, данное место будет зарезервировано под иные нужды и там разместятся произвольные данные, в результате P будет указывать на черт знает что.
Для демонстрации можно выполнить такой пример:

var p:PChar;
   s:string;
   s2:string;
begin
 setlength(s,MAX_PATH);
 setlength(s,GetWindowsDirectory(PChar(s),MAX_PATH));

 p:=PChar(s);
 setlength(s2,1);
 s:=s+"SomeText";
end;


Тоже самое, но добавилась строчка setlength(s2,1);
Рассмотрим еще раз:
p:=PChar(s)
Что s, что P указывают на одну и ту же область памяти.
А потом
setlength(s2,1);
если ничего неожиданного не случится, то менеджер памяти Дельфи выделит под переменную s2 место сразу после s.


 
Piter ©   (2004-04-24 14:06) [5]

В результате, следующая строчка
s:=s+"SomeText";
будет обработана не так, как в предыдущем примере.
Места для добавления "SomeText" по старому адресу уже не хватит (ведь после s идет сразу s2), будет выбрано новое место и s перенесена туда, а "старая" память освобождена. Но P по прежнему ссылается на старое место! После выполнения этого кода, P скорее всего будет указывать на область памяти со значением "c:\windows" (но не факт, так как эта область памяти является свободной и может быть занята чем угодно), а не "c:\windowsSomeText"!
Поэтому будьте внимательны. Если S изменилось, то стоит перепресвоить PChar:
s:=s+"SomeText";
p:=PChar(s);


PChar->String

ну тут все просто. Если P указывает на некую строчку в памяти:

var s:string;
...
s:=p;


То произойдет неявное преобразование типов. При этом строка, на которую указывает p копируется в другую область памяти и s начинает указывать именно туда. В результате, просто появляются две переменные с одинаковыми значениями. И работа их друг от друга не зависит.


 
Piter ©   (2004-04-24 14:06) [5]

В результате, следующая строчка
s:=s+"SomeText";
будет обработана не так, как в предыдущем примере.
Места для добавления "SomeText" по старому адресу уже не хватит (ведь после s идет сразу s2), будет выбрано новое место и s перенесена туда, а "старая" память освобождена. Но P по прежнему ссылается на старое место! После выполнения этого кода, P скорее всего будет указывать на область памяти со значением "c:\windows" (но не факт, так как эта область памяти является свободной и может быть занята чем угодно), а не "c:\windowsSomeText"!
Поэтому будьте внимательны. Если S изменилось, то стоит перепресвоить PChar:
s:=s+"SomeText";
p:=PChar(s);


PChar->String

ну тут все просто. Если P указывает на некую строчку в памяти:

var s:string;
...
s:=p;


То произойдет неявное преобразование типов. При этом строка, на которую указывает p копируется в другую область памяти и s начинает указывать именно туда. В результате, просто появляются две переменные с одинаковыми значениями. И работа их друг от друга не зависит.


 
evvcom ©   (2004-04-24 16:25) [6]

Ко всему этому могу добавить только то, что преобразование String->PChar делайте только при вызове функций, требующих PChar, или при обработке string по указателю без изменения длины этой строки. В противном случае оперируйте непосредственно с переменной string.


 
evvcom ©   (2004-04-24 16:25) [6]

Ко всему этому могу добавить только то, что преобразование String->PChar делайте только при вызове функций, требующих PChar, или при обработке string по указателю без изменения длины этой строки. В противном случае оперируйте непосредственно с переменной string.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.034 c
1-1082576157
Brevis
2004-04-21 23:35
2004.05.09
Basic to Pascal


4-1079600500
ai
2004-03-18 12:01
2004.05.09
Можно ли расположить окно "X" так, чтобы (+)


14-1082474570
Бывающий
2004-04-20 19:22
2004.05.09
Народ где бы надыбить QuickReport 4.03 для C++ Builder 5.0


1-1082363352
Bohdan
2004-04-19 12:29
2004.05.09
TDirectoryListBox - Как показать скрытые директории?


14-1082489341
delphin1
2004-04-20 23:29
2004.05.09
локальная сеть





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский