IPB
ЛогинПароль:

> Правила раздела!

1. Заголовок или название темы должно быть информативным !
2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК !
4. НЕ используйте форум для личного общения!
5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!

 
 Ответить  Открыть новую тему 
> Как скопировать строку PChar ?
Ldnb
сообщение 11.05.2010 4:56
Сообщение #1





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


Думал, что, судя по описанию, функция StrCopy делает полноценное копирование, то есть автоматически выделяет память под копию данных. Как оказалось, нет, копируется только указатель, то есть, если после копирования из буферной переменной её значение меняется, то меняется и "скопированная" строчка.
Так как же всё-таки работать с этим странным PChar?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 11.05.2010 10:12
Сообщение #2


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Перед StrCopy надо заранее выделить память (длина строки + 1 байт на нулевой символ)

> Так как же всё-таки работать с этим странным PChar?

Как? С геморроем...
В современных реализациях Паскаля память автоматом выделяется под строки сколь угодно большой длины, и не надо никакого PChar.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Ldnb
сообщение 11.05.2010 10:32
Сообщение #3





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


К сожалению, надо на Турбо Паскале... ;(

Можно маленький примерчик? Должно быть как-то так?

var p: PChar;
buffer: {буфер длины len}
...
new(p, len+1);
StrCopy(p, buffer);




Кстати, а со StrCat как обстоит дело? Тоже как-то извращаться?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 11.05.2010 10:43
Сообщение #4


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> К сожалению, надо на Турбо Паскале... ;(

Задание такое, что ли? Ну главное из этого задания, я так понял, вы уже усвоили - что строки в стиле ЦЭ есть великое зло.

> Можно маленький примерчик? Должно быть как-то так?

Примерно так, да.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 11.05.2010 13:04
Сообщение #5


Гость






Цитата
Так как же всё-таки работать с этим странным PChar?
Правильно копировать строку, предварительно прочитав имеющуюся документацию по модулю Strings

var P, P1: PChar;
...
P1 := StrNew(P); { <--- Будет создана копия строки P }
...
StrDispose(P1); { <--- Не забываем за собой чистить }


Цитата
Как? С геморроем...
dry.gif "Плохому танцору... " (С) Народная мудрость...
 К началу страницы 
+ Ответить 
Ldnb
сообщение 11.05.2010 18:17
Сообщение #6





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


Спасибо!
А правильно добавить строку p2 к строке p1, стало быть, можно так:
 StrCat(p1, StrNew(P2)); 
?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 11.05.2010 23:09
Сообщение #7


Гость






А как потом освобождать память в таком случае?
 К началу страницы 
+ Ответить 
Ldnb
сообщение 12.05.2010 0:16
Сообщение #8





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


А как правильно? sad.gif Подскажите, пожалуйста.
В общем, какими функциями пользоваться, если требуется работать со строками переменной (большой) длины, дописывая к одним из них копии других, а также строковые константы... Инициализировать их, считывая из файла с помощью буфера путём P1 := StrNew(buf); уже получается, а дальше всё равно лезут глюки...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 12.05.2010 1:18
Сообщение #9


Гость






Хм... Вот так:

uses strings;
var
s: array[0 .. 79] of char;
p, pp, p1, p2: Pchar;
begin
writeln(memavail); { <--- потом сравним, сколько памяти было и сколько осталось }
readln(s);
P := strnew(s);
pp := strnew(s);

p2 := strcat(pp, strnew(p));

p[3] := '8'; { Проверка, действительно ли создается копия строки P }

writeln('p = ', p);
writeln('p2 = ', p2);

strdispose(p2); { <--- Удалять ТОЛЬКО P2, строку PP удалять не надо, она "внутри" P2 }
strdispose(p);
writeln(memavail); { <--- Сравниваем с ранее напечатанным числом }
end.

утечек памяти нет. Если у тебя все еще продолжаются глюки - ты бы привел программу (с заданием). Глядишь, и поправили бы общими усилиями...

Да и вообще, тему по-моему пора переносить в раздел "Задачи", тут уже речь не о теории а именно о реализации.
 К началу страницы 
+ Ответить 
Ldnb
сообщение 12.05.2010 1:37
Сообщение #10





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


Так...значит, всё-таки операция strcat(pp, strnew(p)); корректна, отлично
А как быть в случае дописывания к строке PChar строковой константы? Похоже, здесь и начинались глюки. Попробовать, что ли, так?
 p2 := strcat(pp, strnew(PChar('константа'));
Проверю-ка...

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 12.05.2010 10:03
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Цитата(volvo @ 11.05.2010 14:04) *

dry.gif "Плохому танцору... " (С) Народная мудрость...


Это к чему было? Вы хотите сказать, что только у меня проблемы с этим типом данных? Что утечки памяти и уязвимости, связанные с этим типом, придумал я?

Цитата

p2 := strcat(pp, strnew(PChar('константа'));


На самом деле, прекрасно прокатывает такой код:
p2 := strcat(pp, strnew('const'));
Однако, если забыть про strnew, то появляется утечка.

Сообщение отредактировано: TarasBer - 12.05.2010 10:20


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 12.05.2010 11:58
Сообщение #12


Гость






Цитата
Попробовать, что ли, так?
Так не пойдет, будет утечка памяти.

uses strings;
var
s: array[0 .. 79] of char;
p, pp, p2: Pchar;

begin
writeln(memavail);
readln(s);
pp := strnew(s);

p := nil;
p2 := strcat(pp, strnew(strcat('', strpcopy(p, ' just a test'))));
writeln('p2 = ', p2);

strdispose(p2);
writeln(memavail);
end.

Так - не будет...
 К началу страницы 
+ Ответить 
TarasBer
сообщение 12.05.2010 12:56
Сообщение #13


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Цитата(volvo @ 12.05.2010 12:58) *

Так не пойдет, будет утечка памяти.


Что я делаю не так?
Прикрепленное изображение
Просто приведение к PChar лишний раз не нужно, и всё.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Ldnb
сообщение 13.05.2010 19:41
Сообщение #14





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


blink.gif blink.gif blink.gif blink.gif blink.gif blink.gif
Бился, бился с отладкой программы, переделывал и так и этак, пока не локализовал причину... Если коротко, то причина вот в чём:
{$X+}
uses strings;

var testArr:array [0..1] of PChar;
begin
testArr[0]:= StrNew('!');
testArr[1]:= StrNew('abcdefgh');
StrCat(testArr[0], StrNew(testArr[1]));
write(testArr[1]); readln;
end.


Почему это происходит???? Нет, то есть вроде как приблизительно понятно, почему, но ЭТО ВООБЩЕ НОРМАЛЬНО??? И как это обойти?

{вместо строчки StrCat(testArr[0], StrNew(testArr[1])); можно вставить StrCat(testArr[0], StrNew(PChar('abcdefgh')));
результат не изменится}
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 13.05.2010 21:12
Сообщение #15


Гость






Ты читать умеешь?
Цитата
Declaration:
function StrNew(Str: PChar): PChar;
Все, дальше можешь ничего не делать, уже будет неправильно. Ты НЕ МОЖЕШЬ вместо PChar передать String в функцию. Точка. Разговор с точки зрения компилятора - закончен. В результате функция возвращает все, что угодно, но только не правильный результат. Для конвертации Pascal-евской строки в PChar недостаточно просто написать PChar('string'), это тебе не Дельфи, в Турбо-Паскале для подобных вещей существует
Цитата
StrPCopy (function) (Strings unit)
Copies a Pascal-style string to a null-terminated string.
Declaration:
function StrPCopy(Dest: PChar; Source: String): PChar;

Remarks:
StrPCopy does not perform any length checking.
The destination buffer must have room for at least Length(Source)+1 characters.

(особенно внимательно читай ремарку!!!)

Я бы написал свою функцию, которая будет выделять память под null-terminated строку и копировать туда символы из строки Паскалевской. Тогда твой код перепишется очень просто:

uses strings;

function Convert(s: string): PChar;
var p: Pointer;
begin
GetMem(p, Length(s) + 1);
StrPCopy(PChar(p), s);
Convert := p;
end;

var
testArr: array[0 .. 1] of PChar;
begin
testArr[0] := Convert('!');
testArr[1] := Convert('abcdefgh');

StrLCat(testArr[0], StrNew(testArr[1]), StrLen(testArr[1]) + 1);
writeln(testArr[0]); { Будет выведено '!abcdefgh', я так понимаю, именно это и должно было получиться?}
ReadLn;
end.

Почему не StrCat, а StrLCat? Очень просто: StrCat не осуществляет контроль границ, то есть, если под первый параметр выделено меньше места, чем надо для хранения результата - то последствия будут неприятными. StrLCat же увеличивает размер буфера так, чтобы результат в него поместился (собственно, для этого там и предусмотрен третий параметр)...

Читайте документацию, внимательно читайте, это помогает разобраться...
 К началу страницы 
+ Ответить 
Ldnb
сообщение 14.05.2010 0:11
Сообщение #16





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


За поправление спасибо, учтём, но меня интересует сейчас не writeln(testArr[0]); а то,что выводится в writeln(testArr[1]); проверил, в твоём примере, к сожалению, результат тот же самый...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Ldnb
сообщение 15.05.2010 8:06
Сообщение #17





Группа: Пользователи
Сообщений: 8
Пол: Мужской

Репутация: -  0  +


Эх... видимо нормально работать с PChar всё-таки нельзя, действительно глючный тип, если при попытке что-либо дописать к строке хоть что используй, хоть StrCat, хоть StrLCat, данные могут просто залезть на уже выделенную и используемую в другой переменной память, и затереть её. И потом мучайся отлаживай.


З.Ы. writeln(testArr[1]) выводит 'h'
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 3.05.2024 11:27
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"