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;
最初にメモリ確保したPの値を変えてしまってるからだよ。
メモリ確保した時のPの値は開放するまでカエルとイケないね。
添え字を使った場合は、Pの値をカエルことはないだろ?
それに Inc(P)が1個余計。
> 添え字を使った場合は、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;
> while P <= Pe do
while P < Pe do
としないとTstringListが保持する文字列を渡した場合おかしなことになりますね。
Result := Result+P^;
この処理が原因のような気がするのですが、1mb程度のテキストでも添字を使った方法に比べてかなり遅いでした(ミリ秒単位での話)。
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;
こんな感じでしょうか?
わざわざメモリ操作しなくてもこれでよくない?
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っていう手もあるけど。
> わざわざメモリ操作しなくてもこれでよくない?
そうなんですけど、元発言には...。
# "マチガイは"さんの指摘も活かされてませんし。
質問内容はStringReplaceの最適化ではないですもんね。
あくまで、ソースのエラー特定ですから。
最適化というなら
function SpcToZen(S: string): string; より
procedure SpcToZen(var S: string): だとおもいますし。
ツイート | ![]() |