StrDispose(P); で無効なポインタ操作の実行エラー

解決


QA  2009-04-22 01:07:26  No: 34161

string と PChar の違いをチェックするために以下のようにコーディングしたのですがStrDispose(P);  で「無効なポインタ操作」という実行エラーが出ます。
  しかしコメントのように添え字を使った場合はOKです。これはなぜでしょう?
  'string PChar' ここをぐぐったのですがあまりのも例が多すぎて(笑)。しかし、いくつか見た限りでは適切なQ&Aを見つけられませんでした。
function SpcToZen(S: string): string;//2個の半角空白⇒全角空白
var
  i, L: Integer; //j:    Integer
  P  : PChar;
begin
  if S = '' then Exit;
  L := Length(S);   i := 1;    //j :=0
  P := StrAlloc(L+1);
  try
    while i <= L do
    begin
      if (S[i] = #$20) and (S[i+1] = #$20) then
      begin
        P^ := #$81;    Inc(P); //P[j] := #$81;    P[j+1] := #$40;
        P^ := #$40;
        Inc(i);   Inc(P);      //Inc(i);   Inc(j);
      end
      else
        P^ := S[i];       //P[j] := S[i];
      Inc(i);    Inc(P);  //Inc(i);    Inc(j);
    end;
    P^ := #0;             //P[j] := #0;
    Result := String(P);
  finally
    StrDispose(P);  //ここで実行エラー
  end;
end;


マチガイは  2009-04-22 02:00:36  No: 34162

最初にメモリ確保したPの値を変えてしまってるからだよ。
メモリ確保した時のPの値は開放するまでカエルとイケないね。
添え字を使った場合は、Pの値をカエルことはないだろ?
それに Inc(P)が1個余計。


QA〜こんな感じ?  2009-04-22 10:13:57  No: 34163

> 添え字を使った場合は、Pの値をカエルことはないだろ?
  返事が遅くなりました。そのとおりですね。
  出張先でDelphiがないので確認できないのですが、こんな感じかな?
function SpcToZen(S: string): string;
var
  i:     Integer;
  P, Pe: PChar;
begin
  if S = '' then Exit;
  Result := '';
  i := 1;
  P := PChar(S);     //先頭
  Inc(P, Strlen(P)); //末端
  Pe := P;           //末端を記憶
  P := PChar(S);     //先頭に戻す

  while P <= Pe do
  begin
    if (S[i] = #$20) and (S[i+1] = #$20) then
    begin
      Result := Result+#$81+#$40;
      Inc(P);  Inc(i);
    end
    else
      Result := Result+P^;
    Inc(i);    Inc(P);
  end;
end;


QA  2009-04-22 19:01:46  No: 34164

>  while P <= Pe do
  while P < Pe do
としないとTstringListが保持する文字列を渡した場合おかしなことになりますね。
      Result := Result+P^;
  この処理が原因のような気がするのですが、1mb程度のテキストでも添字を使った方法に比べてかなり遅いでした(ミリ秒単位での話)。


DEKO  2009-04-23 05:45:26  No: 34165

function SpcToZen(S: string): string;
var
  Src, Dst, P: PChar;
begin
  if Length(S) = 0 then
    Exit;
  P := StrAlloc(Length(S)+1);
  Dst := P;
  try
    Src := PChar(S);
    while (Src^ <> #$00) do
      begin
        if (Src^ = #$20) and ((Src+1)^ = #$20) then
          begin
            Dst^ := #$81;
            Inc(Src);
            Inc(Dst);
            Dst^ := #$40;
          end
        else
          Dst^ := Src^;
        Inc(Src);
        Inc(Dst);
      end;
    Dst^ := #$00;
    result := StrPas(P);
  finally
    StrDispose(P);
  end;
end;

こんな感じでしょうか?


ん?  2009-04-23 07:01:09  No: 34166

わざわざメモリ操作しなくてもこれでよくない?

L := Length(S);
SetLength(result, L);
i := 1;
while i <= L do
begin
  if (S[i] = #$20) and (S[i+1] = #$20) then
  begin
    result[i] := #$81;
    result[i + 1] := #$40;
    Inc(i, 2);
  end
  else
    result[i] := S[i];
    Inc(i);
  end;
end;

StringReplaceっていう手もあるけど。


DEKO  2009-04-23 07:35:37  No: 34167

> わざわざメモリ操作しなくてもこれでよくない?
そうなんですけど、元発言には...。

# "マチガイは"さんの指摘も活かされてませんし。


monaa  2009-04-23 17:18:55  No: 34168

質問内容はStringReplaceの最適化ではないですもんね。
あくまで、ソースのエラー特定ですから。
最適化というなら
function SpcToZen(S: string): string;  より
procedure SpcToZen(var S: string):  だとおもいますし。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加