Думал, что, судя по описанию, функция StrCopy делает полноценное копирование, то есть автоматически выделяет память под копию данных. Как оказалось, нет, копируется только указатель, то есть, если после копирования из буферной переменной её значение меняется, то меняется и "скопированная" строчка. Так как же всё-таки работать с этим странным PChar?
TarasBer
11.05.2010 14:12
Перед StrCopy надо заранее выделить память (длина строки + 1 байт на нулевой символ)
> Так как же всё-таки работать с этим странным PChar?
Как? С геморроем... В современных реализациях Паскаля память автоматом выделяется под строки сколь угодно большой длины, и не надо никакого PChar.
Ldnb
11.05.2010 14:32
К сожалению, надо на Турбо Паскале... ;(
Можно маленький примерчик? Должно быть как-то так?
var p: PChar; buffer: {буфер длины len} ... new(p, len+1); StrCopy(p, buffer);
Кстати, а со StrCat как обстоит дело? Тоже как-то извращаться?
TarasBer
11.05.2010 14:43
> К сожалению, надо на Турбо Паскале... ;(
Задание такое, что ли? Ну главное из этого задания, я так понял, вы уже усвоили - что строки в стиле ЦЭ есть великое зло.
> Можно маленький примерчик? Должно быть как-то так?
Примерно так, да.
volvo
11.05.2010 17:04
Цитата
Так как же всё-таки работать с этим странным PChar?
Правильно копировать строку, предварительно прочитав имеющуюся документацию по модулю Strings
var P, P1: PChar; ... P1 := StrNew(P); { <--- Будет создана копия строки P } ... StrDispose(P1); { <--- Не забываем за собой чистить }
Цитата
Как? С геморроем...
"Плохому танцору... " (С) Народная мудрость...
Ldnb
11.05.2010 22:17
Спасибо! А правильно добавить строку p2 к строке p1, стало быть, можно так:
StrCat(p1, StrNew(P2));
?
volvo
12.05.2010 3:09
А как потом освобождать память в таком случае?
Ldnb
12.05.2010 4:16
А как правильно? Подскажите, пожалуйста. В общем, какими функциями пользоваться, если требуется работать со строками переменной (большой) длины, дописывая к одним из них копии других, а также строковые константы... Инициализировать их, считывая из файла с помощью буфера путём P1 := StrNew(buf); уже получается, а дальше всё равно лезут глюки...
volvo
12.05.2010 5:18
Хм... Вот так:
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 5:37
Так...значит, всё-таки операция strcat(pp, strnew(p)); корректна, отлично А как быть в случае дописывания к строке PChar строковой константы? Похоже, здесь и начинались глюки. Попробовать, что ли, так?
p2 := strcat(pp, strnew(PChar('константа'));
Проверю-ка...
TarasBer
12.05.2010 14:03
Цитата(volvo @ 11.05.2010 14:04)
"Плохому танцору... " (С) Народная мудрость...
Это к чему было? Вы хотите сказать, что только у меня проблемы с этим типом данных? Что утечки памяти и уязвимости, связанные с этим типом, придумал я?
Цитата
p2 := strcat(pp, strnew(PChar('константа'));
На самом деле, прекрасно прокатывает такой код: p2 := strcat(pp, strnew('const')); Однако, если забыть про strnew, то появляется утечка.
volvo
12.05.2010 15:58
Цитата
Попробовать, что ли, так?
Так не пойдет, будет утечка памяти.
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);
Бился, бился с отладкой программы, переделывал и так и этак, пока не локализовал причину... Если коротко, то причина вот в чём:
{$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'))); результат не изменится}
volvo
14.05.2010 1:12
Ты читать умеешь?
Цитата
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 4:11
За поправление спасибо, учтём, но меня интересует сейчас не writeln(testArr[0]); а то,что выводится в writeln(testArr[1]); проверил, в твоём примере, к сожалению, результат тот же самый...
Ldnb
15.05.2010 12:06
Эх... видимо нормально работать с PChar всё-таки нельзя, действительно глючный тип, если при попытке что-либо дописать к строке хоть что используй, хоть StrCat, хоть StrLCat, данные могут просто залезть на уже выделенную и используемую в другой переменной память, и затереть её. И потом мучайся отлаживай.
З.Ы. writeln(testArr[1]) выводит 'h'
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.