1. Заголовок или название темы должно быть информативным ! 2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code]. 3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК ! 4.НЕ используйте форум для личного общения! 5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!
Думал, что, судя по описанию, функция StrCopy делает полноценное копирование, то есть автоматически выделяет память под копию данных. Как оказалось, нет, копируется только указатель, то есть, если после копирования из буферной переменной её значение меняется, то меняется и "скопированная" строчка. Так как же всё-таки работать с этим странным PChar?
А как правильно? Подскажите, пожалуйста. В общем, какими функциями пользоваться, если требуется работать со строками переменной (большой) длины, дописывая к одним из них копии других, а также строковые константы... Инициализировать их, считывая из файла с помощью буфера путём P1 := StrNew(buf); уже получается, а дальше всё равно лезут глюки...
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.
утечек памяти нет. Если у тебя все еще продолжаются глюки - ты бы привел программу (с заданием). Глядишь, и поправили бы общими усилиями...
Да и вообще, тему по-моему пора переносить в раздел "Задачи", тут уже речь не о теории а именно о реализации.
Так...значит, всё-таки операция strcat(pp, strnew(p)); корректна, отлично А как быть в случае дописывания к строке PChar строковой константы? Похоже, здесь и начинались глюки. Попробовать, что ли, так?
Это к чему было? Вы хотите сказать, что только у меня проблемы с этим типом данных? Что утечки памяти и уязвимости, связанные с этим типом, придумал я?
Цитата
p2 := strcat(pp, strnew(PChar('константа'));
На самом деле, прекрасно прокатывает такой код: p2 := strcat(pp, strnew('const')); Однако, если забыть про strnew, то появляется утечка.
Бился, бился с отладкой программы, переделывал и так и этак, пока не локализовал причину... Если коротко, то причина вот в чём:
{$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'))); результат не изменится}
Все, дальше можешь ничего не делать, уже будет неправильно. Ты НЕ МОЖЕШЬ вместо 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 же увеличивает размер буфера так, чтобы результат в него поместился (собственно, для этого там и предусмотрен третий параметр)...
Читайте документацию, внимательно читайте, это помогает разобраться...
За поправление спасибо, учтём, но меня интересует сейчас не writeln(testArr[0]); а то,что выводится в writeln(testArr[1]); проверил, в твоём примере, к сожалению, результат тот же самый...
Эх... видимо нормально работать с PChar всё-таки нельзя, действительно глючный тип, если при попытке что-либо дописать к строке хоть что используй, хоть StrCat, хоть StrLCat, данные могут просто залезть на уже выделенную и используемую в другой переменной память, и затереть её. И потом мучайся отлаживай.