原則として、絶対にしないでください。 ユーザー提供のバッファーで解放または再割り当てを行います。ユーザーが領域を割り当てた場所 (モジュール内、別の DLL) がわからないため、ユーザー バッファーで割り当て関数を使用することはできません。
関数内で再割り当てを行うことができない場合は、置換を 1 回だけ行うなど、動作を少し変更する必要があります。これにより、ユーザーは結果の文字列の最大長を計算し、これに十分な長さのバッファーを提供できるようになります。
次に、複数の置換を行う別の関数を作成できますが、結果の文字列にスペース全体を割り当て、ユーザー入力文字列をコピーする必要があります。次に、割り当てた文字列を削除する方法を提供する必要があります。
結果:
void strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void strrepmfree(char *input);
まず、パーティーに遅れてすみません。これは私の最初のスタックオーバーフローの回答です。 :)
指摘されているように、realloc() が呼び出されると、再割り当てされるメモリへのポインタを変更できる可能性があります。この場合、引数「string」は無効になります。再割り当てしても、関数が終了すると変更は範囲外になります。
OP に答えるために、 realloc() は新しく再割り当てされたメモリへのポインタを返します。戻り値はどこかに保存する必要があります。通常、次のようにします:
data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));
/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
foo = bar;
bar = NULL;
}
else
{
fprintf(stderr, "Crap. Memory error.\n");
free(foo);
exit(-1);
}
TyBoer が指摘しているように、この関数への入力として渡されるポインターの値を変更することはできません。好きなように割り当てることができますが、変更は関数の最後で範囲外になります。次のブロックでは、関数が完了すると、「入力」は無効なポインターになる場合とそうでない場合があります:
void foobar(char *input, int newlength)
{
/* Here, I ignore my own advice to save space. Check your return values! */
input = realloc(input, newlength * sizeof(char));
}
マークは、関数の出力として新しいポインターを返すことで、これを回避しようとします。これを行うと、入力に使用したポインターを二度と使用しないという責任が呼び出し元にあります。戻り値と一致する場合、同じ場所への 2 つのポインターがあり、そのうちの 1 つで free() を呼び出すだけで済みます。それらが一致しない場合、入力ポインターは、プロセスが所有している場合と所有していない場合があるメモリを指すようになりました。逆参照すると、セグメンテーション違反が発生する可能性があります。
次のように、入力にダブル ポインターを使用できます。
void foobar(char **input, int newlength)
{
*input = realloc(*input, newlength * sizeof(char));
}
呼び出し元が入力ポインターの複製をどこかに持っている場合、その複製は今でも無効である可能性があります。
ここでの最もクリーンな解決策は、関数呼び出し元の入力を変更しようとするときに realloc() を使用しないことだと思います。新しいバッファを malloc() して返し、古いテキストを解放するかどうかを呼び出し元に決定させるだけです。これには、呼び出し元が元の文字列を保持できるという追加の利点があります!
まだ試していないので、暗闇の中でのショットですが、再割り当てすると、malloc と同じようにポインターが返されます。 realloc は必要に応じてポインターを移動できるため、次のことを行わないと、無効なポインターを操作している可能性が高くなります:
input = realloc(input, strlen(input) + delta);