![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как привести строку или число к типу Char? [D5, Win2k]
nikolo © (2002-08-16 16:40:00)Всем привет! У меня есть строка или число > 0 и < 10. Как я могу привести эту строку и число к типу Char?
Помогите, срочно надо!
nikolo (2002-08-20 15:02:00) [1]Все понятно, всем спасибо. Тему закрываем.
Юрий Зотов (2002-08-20 14:34:00) [2]Вот же Фома неверующий. Ведь давным-давно было сказано:
1. PChar - это УКАЗАТЕЛЬ, а не массив.
2. Под ТЕЛО массива надо выделить ПАМЯТЬ.
3. А потом ее ОСВОБОДИТЬ.
Почему Вы СРАЗУ не прислушались к этим словам - не знаю. Конечно, вольному воля, но в итоге Вы потеряли кучу времени, измучили и себя, и форум.
У Вас PChar"ный Result получает адрес памяти, которая выделена не специально для него, а была автоматически выделена компилятором под тело ЛОКАЛЬНОЙ строки. Поскольку строка ЛОКАЛЬНАЯ, то при завершении функции эта память тем же компилятором так же автоматически освобождается. И на что после этого указывает Result? На то, чего уже нет. Отсюда и Access Violation.
И еще надо подумать о том, ГДЕ выделять и ГДЕ освобождать память. Обычная практика - где выделяется, там и освобождается, тогда не будет проблем с менеджером памяти. Поскольку результат должен быть передан в EXE, то в DLL память освобождать нельзя, это надо делать в EXE. Значит, и выделять память нужно тоже в EXE.
Короче говоря, вот работающий пример.
// Процедура в DLL.
procedure Proc(Src, Dest: PChar); // Если надо, поставьте stdcall
var
S: string;
begin
// Что-то делаем с исходной строкой. О выделении памяти под тело
// строки S не заботимся, этим управляет компилятор.
S := "Ура! Мы изменили " + String(Src);
// Записываем результат по адресу Dest. Это самое важное, потому что
// при завершении Proc память, выделенная под тело S будет освобождена.
// Внимание! Это всего лишь пример! Поэтому здесь не проверяется
// размер участка памяти, которую адресует Dest. Если он окажется
// недостаточным, возможны любые ошибки.
StrCopy(Dest, PChar(S))
end;
// Вызов из основной программы.
procedure TForm1.Button1Click(Sender: TObject);
var
P: PChar;
begin
// Выделяем память под результат работы Proc. Внимание!!! Если
// этих 512 байт окажется мало, возможно что угодно.
GetMem(P, 512);
try
// Преобразуем Edit1.Text с помошью Proc
Proc(PChar(Edit1.Text), P);
// Переносим результат в Edit2.Text
Edit2.Text := String(P)
finally
// Освобождаем выделенную память
FreeMem(P, 512)
end
end;
Digitman (2002-08-20 12:19:00) [3]>nikolo
Function TfmMain.FFF(pParam: PChar): PChar;
Var
S: String;
Begin
S := StrPas(pParam);
S := S+" 222";
// результат функции есть просто указатель на блок памяти
// который при возврате из ф-ции должен содержать строку символов
// ограниченную справа символом-терминатором
// вопрос : откуда он возьмется, этот самый блок памяти ?
// не сам же по себе будет выделен !
// нужно об этом позаботиться
GetMem(Result, Length(S) + 1); // вот здесь и выделим его
// а теперь - смело копируем содержимое некоей строки S в этот блок
StrLCopy(Result, // адрес результирующего блока
PChar(S), // адрес блока, распределенного автоматически для исходной копируемой строки
Length(S) + 1); // размер копируемого блока (включая байт с символом-терминатором)
End;
nikolo (2002-08-20 12:02:00) [4]АУ!!!!
nikolo (2002-08-20 11:44:00) [5]Ребята, ответьте, пожалуйста, на мой последний вопрос...
Юрий Зотов (2002-08-19 22:54:00) [6]> Юрий Зотов © (19.08.02 22:39)
Дорогой Юрий, прими поздравления от самого себя! И больше не путай адрес массива с его длиной!
:о)
> Толик © (19.08.02 15:00)
Но все равно предел длины - 4 Гб (теоретический, а практический намного меньше). Просто 4 Гб - это все адресное пространство процесса (почему - написано выше) и за его пределами находиться вообще ничего не может. А нашей программе доступны даже не все 4 Гб (не помню наизусть, надо посмотреть в книжке, но что-то типа 2 Гб - причем эта цифра для 9х и NT разная).
Юрий Зотов (2002-08-19 22:39:00) [7]> Толик © (19.08.02 15:00)
Как и любой другой указатель, PChar в Win32 занимает 4 байта - то есть, 32 бита. Следовательно, минимальный адрес, который он может содержать - это 32 нуля (то есть, ноль), а максимальный - 32 единички (то есть, 4 Гб).
В Win32 ЛЮБОЙ указатель может адресовать в пределах 4 Гб. Вот когда перейдем на 64-битные системы - тогда картина будет другая.
nikolo (2002-08-19 16:00:00) [8]Ты знаешь, Access violation вылазит... В чем может быть дело?
Делаю так:
Function TfmMain.FFF(pParam: PChar): PChar;
Var
S: String;
Begin
S := StrPas(pParam);
S := S+" 222";
StrLCopy(Result, PChar(S), Length(S) + 1);
End;
procedure TfmMain.Button1Click(Sender: TObject);
Var SS: String;
Begin
SS := "111";
Label1.Caption := FFF(PChar(SS));
end;
Skier (2002-08-19 15:39:00) [9]>nikolo
if Result = nil then; - это выбрось :)
Skier (2002-08-19 15:38:00) [10]>nikolo
Function FFF(pParam: PChar): PChar;
Var
S: String;
Begin
S := StrPas(pParam);
//.....
StrLCopy(Result, PChar(S), Length(S) + 1);
if Result = nil then;
End;
nikolo (2002-08-19 15:21:00) [11]Есть основная программа, к ней подключается dll, в которой нужно реализовать несколько функций для работы со строками. А вызываться эти функции будут из основной программы. Т.е. в основной программе, например, будет что-то типа:
Label1.Caption := FFF(ed.Text);
Skier (2002-08-19 15:15:00) [12]>nikolo
Скажи мне такую вещь : как ты планируешь (и где) использовать
результат функции FFF ?
nikolo (2002-08-19 15:09:00) [13]> Skier ©, ты писал уже:
Var
Dest: PChar;
cc: Char;
Begin
Dest := AllocMem(4);
try
cc := "7";
Dest[3] := cc;
finally
FreeMem(Dest, 4);
end;
End;
но не понятно, как реализовать мне работу именно со String внутри функции, а не с PChar? Что значит "выделить память под PChar и скопировать в неё String"?
Не мог бы на примере показать как реализовать такую функцию:
Function FFF(pParam: PChar): PChar;
Var
S: String;
Begin
S := StrPas(pParam);
.....
действия с S
.....
Result := PChar(S);
End;
Толик (2002-08-19 15:00:00) [14]Прошу прощения, что вмешиваюсь в обсуждение, но возник вопрос к Юрий Зотов © (16.08.02 23:40).
А почему pchar может указывать только на массив не более 4Гб??? А на 4Гб + 1 байт ему силёнок не хватает??? Там же ни где не хранится размер массива, ограниченный размерностью longword.
Или я что-то упустил?
Skier (2002-08-19 14:48:00) [15]>nikolo
Нет. Так нельзя !
Вот выдержка из Help-a :
A common error when working with PChars is to store in a data structure, or return as a value, a local variable. When your routine ends, the PChar will disappear because it is simply a pointer to memory, and is not a reference counted copy of the string. For example:
function title(n: Integer): PChar;
var
s: string;
begin
s := Format("title - %d", [n]);
Result := PChar(s); // DON"T DO THISend;
This example returns a pointer to string data that is freed when the title function returns.
В твоём случае нужно выделить память под PChar и
скопировать в неё String;
nikolo (2002-08-19 14:44:00) [16]Грубо говоря, я могу в функцию dll написать следующим образом?
Function FFF(pParam: PChar): PChar;
Var
S: String;
Begin
S := StrPas(pParam);
.....
действия с S
.....
Result := PChar(S);
End;
Или нужно как-то иначе работать с PChar внутри функции?
Юрий Зотов (2002-08-16 23:40:00) [17]> Как я могу привести эту строку и число к типу Char?
Строку - никак. Char - это один символ, а в строке их может быть несколько, как же ее приведешь? А число от 0 до 9 - запросто, по таблице ASCII. Как уже говорил MBo:
Ch := Char(Ord("0") + число);
> в функциях dll можно объявлять локальные переменные типа String
И локальные, и глобальные - можно, без малейших проблем. Проблемы возникают только тогда, когда такие переменные используются в ПАРАМЕТРАХ процедур и функций из DLL. В этом случае самое простое - в uses и DLL, и работающего с ней EXE прописать ShareMem (строго в самих DPR и строго самым первым). Тогда не нужно будет никаких PChar, но с такой DLL сможет работать только Delphi-программа. Если же нужно, чтобы эту DLL могла использовать вообще любая программа, то параметры должны быть только PChar.
> ведь PChar - это массив символов, заканчивающийся #0...
Нет. Это УКАЗАТЕЛЬ на массив символов, заканчивающийся #0. Сам этот указатель статический и всегда занимает 4 байта. А вот массив, на который он указывает может быть до 4 Гб, но память под него должна выделить Ваша программа. А после использования, конечно, освободить.
Bars (2002-08-16 23:12:00) [18]Procedure .....
var
Str:string;
Int:integer;
Pch:Pchar;
begin
Pch:=pchar(Str); // или Pch:=pchar(Int)
// или
Procedure .....
var
Str:string;
Int:integer;
Pch:char;
begin
Pch:=char(Str); // или ch:=pchar(Int)
Dmitriy Polskoy (2002-08-16 18:15:00) [19]Попробуй так:
function FFF(PSt: PChar): PChar;
var St: String;
begin
St := StrPas(PSt);
...
St[Ord(Length(St)) + 1] := #0;
Result := @St[1];
end;
Skier (2002-08-16 18:13:00) [20]>nikolo
Это с передачей String в качестве параметра - проблемы,
а использовать String внутри функции в DLL можно на УРА.