GetMem для одной переменной PChar изменяет содержимое другой переменной PChar

Итак, у меня следующая проблема. У меня есть 2 переменные PChar. Выделяю память под первую, делаю какие-то операции, выделяю память под вторую переменную - и на этом шаге первая переменная содержит неверное значение (видел при отладке). Вот код:

procedure TReadThread.Execute;
Var
  iRead, temp, i, count : Integer;
  header, params : PChar;
begin
  try
    GetMem(header, 12);
    iRead := recv(FSocket, header^, 12, 0);

    if (iRead<>12) then
      raise Exception.Create('Header recieving problem!');

    temp := StrToIntDef(String(copy(header,3,4)),0);

    if (temp=0) then
      raise Exception.Create('Body receiving problem!');

    count := temp*SizeOf(Char);

    if (count+12<=16384) then
      begin
        GetMem(params, count);
        iRead := recv(FSocket, params^, count, 0);

        if (iRead<>count) then
          raise Exception.Create('Cant recieve messsage fully!');
      end
    else
      raise Exception.Create('Bad message size (>16 KB)!');

    GetMem(FText, temp*SizeOf(Char)+12);
    FText := PChar(String(header) + String(params));

    FreeMem(header);
    FreeMem(params);
  except
    on E : Exception do
      ShowMessage(E.Message);
  end;
end;

На линии

iRead := recv(FSocket, params^, count, 0);

Когда я искал значение переменной HEADER — я увидел что-то удивительное — не то же самое, что я видел в начале процедуры. Как я могу это исправить?


person Dmitry Belaventsev    schedule 21.05.2011    source источник
comment
Разве вы не хотите сделать PChar PAnsiChar? и заменить SizeOf(Char) на SizeOf(AnsiChar) ?   -  person Johan    schedule 22.05.2011
comment
и какова цель этого изменения?   -  person Dmitry Belaventsev    schedule 22.05.2011
comment
Ansichar занимает всего 1 байт, Char в Delphi2010 занимает 2 байта. Смотрите ответ ниже.   -  person Johan    schedule 22.05.2011
comment
Я не вижу причин для изменения заголовка GetMem(params, count);. Единственная очевидная проблема, которую я вижу, - это та, которую указал Дэвид, то есть утечка памяти FText при каждом вызове + сохранение висячего указателя.   -  person Ken Bourassa    schedule 22.05.2011
comment
Я делаю FreeMem(FText) в деструкторе потока.   -  person Dmitry Belaventsev    schedule 22.05.2011


Ответы (2)


Я предполагаю, что FText является PChar. Поскольку вы говорите, что используете Delphi 2010, вы должны знать, что Char на самом деле является синонимом WideChar и имеет ширину 2 байта. Я подозреваю, что вы действительно хотите использовать AnsiChar.

Самая вопиющая проблема заключается в том, что вы выделяете память для FText, а затем сбрасываете ее с присвоением FText. Более того, память, на которую ссылается FText, уничтожается по завершении процедуры.

Я думаю, что вам, вероятно, следует сделать следующее:

  • Переключитесь на AnsiChar для recv вызовов.
  • Измените FText на AnsiString.
  • Полностью прекратите использовать GetMem и используйте выделение стека.

Возможно что-то вроде этого:

procedure TReadThread.Execute;
Var
  iRead, count: Integer;
  header: array [0..12-1] of AnsiChar;
  params: array [0..16384-1] of AnsiChar;
begin
  try
    iRead := recv(FSocket, header, 12, 0);

    if (iRead<>12) then
      raise Exception.Create('Header receiving problem!');

    count := StrToIntDef(Copy(header,3,4),0);

    if (count=0) then
      raise Exception.Create('Body receiving problem!');

    if (count+12<=16384) then
      begin
        iRead := recv(FSocket, params, count, 0);
        if (iRead<>count) then
          raise Exception.Create('Cant receive messsage fully!');
      end
    else
      raise Exception.Create('Bad message size (>16 KB)!');

    SetLength(FText, 12+count);
    Move(header, FText[1], 12);
    Move(params, FText[13], count);
  except
    on E : Exception do
      ShowMessage(E.Message);
  end;
end;
person David Heffernan    schedule 21.05.2011
comment
+1 за то, что больше не использую getmem. Обратите внимание, что вы также можете использовать: var header: ansistring; begin SetLength(header,12); для создания строки длиной 12, которая автоматически уничтожается при выходе из подпрограммы. Учитывая тот факт, что размер стека составляет 1 МБ, создание переменной размером 16 КБ выглядит прекрасным решением. - person Johan; 22.05.2011

КАК Дэвид Хеффернан Саид раньше. Char имеет 2 байта, а также pChar указывает на символ Unicode в Delphi 2010, но код Дэвида имеет 2 проблемы.

  1. Если вы хотите получить международные символы (строки Unicode или utf8), вы не можете использовать AnsiChar

  2. Если определить переменную params как Array [0..16384-1] AnsiChar, вы потеряете производительность своей программы. локальные переменные будут использовать стек и определять параметры, как определено Дэвидом, будут занимать пространство стека.

для ответа вы можете использовать свой код с помощью 1 простых изменений. определите только переменную заголовка и параметров как PAnsiChar. вы можете оставить другие коды без изменений.

заголовок, параметры: PAnsiChar;

person Mahdi    schedule 28.06.2011