Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как привести строку или число к типу Char? [D5, Win2k]


Страницы:   1 2

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 можно на УРА.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо