2014-01-02 2 views
1

Здесь у меня есть несколько строк кода DELPHI, работающих в Delphi 7:Дельфи недопустимая операция указатель

var 
     ptr:Pointer ; 
    begin 
     ptr:=AllocMem(40); 
     ptr:=Pchar('OneNationUnderGod'); 
     if ptr<>nil then 
     FreeMem(ptr); 
    end; 

После запуска этот фрагмент кода, FreeMem(ptr) выдаст сообщение об ошибке: «недопустимой операции указателя». Если я удалю предложение:

 ptr:=Pchar('OneNationUnderGod'); 

то ошибки не будет. Теперь у меня есть два вопроса:

1. Почему это происходит? 2. Если мне нужно использовать предложение Pchar, как мне освободить память, выделенную ранее?

Большое спасибо за вашу помощь!

ответ

5

Проблема в том, что вы изменяете адрес, содержащийся в переменной ptr.

Вы вызываете AllocMem для выделения буфера, на который вы ссылаетесь, используя ptr. Это хорошо. Но вы никогда не должны изменять значение ptr, адрес буфера. И вы его меняете.

Вы писали:

ptr:=AllocMem(40); 
ptr:=Pchar('OneNationUnderGod'); 

Вторая строка является проблемой. Вы изменили ptr, и теперь ptr ссылается на что-то другое (строковый литерал, хранящийся в постоянной памяти, когда это происходит). Теперь вы потеряли следы буфера, выделенного вашим вызовом AllocMem. Вы спросили AllocMem о новом блоке памяти и сразу же отбросили этот блок памяти.

Что вы, по-видимому, хотите сделать, это скопировать строку. Возможно, как это:

ptr := AllocMem(40); 
StrCopy(ptr, 'OneNationUnderGod'); 

Теперь мы прекрасно назвать FreeMem, потому что PTR по-прежнему содержит адрес, что вызов AllocMem предусмотрено.

ptr := AllocMem(40); 
try 
    StrCpy(ptr, 'OneNationUnderGod'); 
    // do stuff with ptr 
finally 
    FreeMem(ptr); 
end; 

Очевидно, что в реальном коде вы бы найти лучший и более надежный способ определения длины буфера, чем жестко кодированные значения.

В вашем коде, при условии, что указанное исправление применяется, тест на ptr, являющийся нолем, бесполезен. AllocMem никогда не возвращает ниль. Отказ AllocMem приводит к возникновению исключения.


Сказав все это, обычным способом работать с строковыми буферами обычно нет. Нормально использовать строки Delphi. Если вам нужен PChar, например, для использования с interop, сделайте одно с PChar (str), где str имеет строку типа.

Вы говорите, что вы должны использовать динамически распределенные буферы PChar. Возможно, это так, но я очень сомневаюсь в этом.

+0

AFAIR в Delphi, который является strcOpy ;-) и, возможно, StrLCopy будет еще более надежным шаблоном вообще –

+0

@ Arioch'The Спасибо за исправление. StrLCopy может быть хорошим. Но я думаю, что всегда использовал строку и PChar(). StrCopy иногда отлично, если вы выделяете правильный размер буфера. Если вы вызвали StrLen, то Move - как я это сделаю. –

+0

Нет, я просто вижу StrLCopy как предел безопасности, сразу после выделения, такого как AllocMem (const) выше. После преобразования большого количества кода, например move (x, y, sizeof (y)) в Unicode :-D –

1

Он падает, потому что вы освобождаете статическую память, которая не была динамически распределена. Нет необходимости в свободной памяти, используемой литералами вообще. Только свободная память, которая динамически распределяется.

+0

, но я создал ptr, используя AllocMem (40), разве этот блок памяти ptr не выделяется динамически? –

+2

Возможно, иначе, OP не заметил, что назначение PChar означает, что ptr больше не указывает на память, выделенную AllocMem? – MartynA

+0

спасибо, @Remy Lebeau –

1

Я попытался бы сделать то, что вы сделали более явным. Кажется, вы ошибочно называете имя переменной с ее значением.Однако на самом деле - с учетом ценности - то, что вы делали, было

ptrA:=AllocMem(40); 
ptrB:=Pchar('OneNationUnderGod'); 
if ptrB<>nil then 
    FreeMem(ptrB); 

Каждое новое назначение изменяет значение перезаписи предыдущего, таким образом, вы освободив другой указатель, который был выделен.

Вы можете прочитать документацию для функций, таких как StrNew, StrDispose, StrCopy, StrLCopy и примеры кода, чтобы увидеть некоторые шаблоны работы с строками PChar.

Смежные вопросы