1

を移動して操作するには、次のアプローチを使用しますAnsiString。ほとんどの場合は機能しますが、文字列へのポインターが機能しなくなることがあります。次のコードがあるとします。

var
  s: AnsiString;
  p: PAnsiChar;
  offset, idx, cnt: Integer;
begin
  s := 'some>very>long>string>with>field>delimiters>';
  p := @s[1];
  offset := 1;

  // find the 5th field
  cnt := 5;
  repeat
    idx := AnsiString.AnsiPos('>', p);
    Inc(p, idx);
    Inc(offset, idx);
    Dec(cnt);
  until cnt = 0;

  // insert a new field after the 5th field
  Insert(AnsiString('something new>'), s, offset);

  // skip other fields
  // insert other values
  // repeat
end;

デバッグ時、ループが終了した直後にrepeat..untilインスペクタを見て、それを確認できますp = 'field>delimiters>'Insert()ステートメントの後、s = 'some>very>long>string>with>something new>field>delimiters>'およびp = 'something new>field>delimiters>'インスペクターで。これは予想通りです。

私の実際の文字列は数千文字の長さです。文字列を移動して新しいフィールドを追加するこの方法は、何十回も機能しますが、突然機能しなくなります。 pの呼び出し後、文字列の先頭に挿入された値が表示されなくなりましたInsert()pそれが変わったことを知らないようですs...

ほとんどのステートメントの後pに文字を適切に参照し、いくつかの呼び出しの後に突然動作を停止するのはなぜですか?sInsert()Insert()

(質問を入力しているときに答えを見つけました。答えは今では明らかですが、問題に苦しんでいる間はそうではありません。おそらく質問と答えを投稿すると、他の人の助けになるでしょう...)

4

1 に答える 1

7

を呼び出すと、現在のメモリ位置でバッファを拡張するのに十分な追加の連続メモリがない場合Insert()、メモリ マネージャは をメモリ内の新しい位置に移動します。AnsiStringこれによりp、変更された文字列を保持しない古いメモリ位置が指されたままになり、アクセス違反が発生する可能性があります。

pInsert()ステートメントの後に再初期化するコードを 1 行追加すると、問題が修正されます。

var
  s: AnsiString;
  p: PAnsiChar;
  offset, idx, cnt: Integer;
begin
  s := 'some>very>long>string>with>field>delimiters>';
  p := @s[1];
  offset := 1;

  // find the 5th field
  cnt := 5;
  repeat
    idx := AnsiString.AnsiPos('>', p);
    Inc(p, idx);
    Inc(offset, idx);
    Dec(cnt);
  until cnt = 0;

  // insert a new field after the 5th field
  Insert(AnsiString('something new>'), s, offset);
  p := @s[offset];                                 // <- this fixes the issue

  // skip other fields
  // insert other values
  // repeat
end;
于 2013-02-22T01:31:57.327 に答える