いいえ、関数内でローカル文字列へのポインターを返すことは安全ではありません。C はそれを止めることはありません (ただし、要求するとコンパイラが警告することがあります。この場合、return_string
コードを に変更しない限り、ローカル変数によって警告が表示されなくなりますreturn filled_buffer;
)。しかし、それは安全ではありません。基本的に、スペースは他の関数によって再利用されるため、以前はきれいにフォーマットされていた文字列を楽しそうに踏みにじっています。
このコメントについて詳しく説明していただけますか — 「いいえ、安全ではありません...」
ローカル変数 (文字列定数とは対照的に) は、関数が戻るときに範囲外になります。スコープ外の変数へのポインターを返すことは未定義の動作であり、何としても避けるべきものです。未定義の動作を呼び出すと、プログラムが動作しているように見えることを含め、あらゆることが発生する可能性があり、プログラムがハード ドライブを再フォーマットしたとしても、苦情の根拠はありません。さらに、同じことが異なるマシンで発生することは保証されていません。また、現在のマシンで同じコンパイラの異なるバージョンを使用していても、同じことが起こるとは限りません。
出力バッファを関数に渡すか、関数を使用malloc()
して、呼び出し元の関数によって返され解放されるメモリを割り当てます。
出力バッファを関数に渡す
#include <stdio.h>
#include <string.h>
int reverse_string(char *input_string, char *buffer, size_t bufsiz);
int reverse_string(char *input_string, char *buffer, size_t bufsiz)
{
size_t j = 0;
size_t i = strlen(input_string);
if (i >= bufsiz)
return -1;
buffer[i] = '\0';
while (i != 0)
{
buffer[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", buffer);
return 0;
}
int main (void)
{
char buffer[16];
if (reverse_string("tasdflkj", buffer, sizeof(buffer)) == 0)
printf("%s\n", buffer);
return 0;
}
メモリ割り当て
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse_string(char *input_string);
char *reverse_string(char *input_string)
{
size_t j = 0;
size_t i = strlen(input_string) + 1;
char *string = malloc(i);
if (string != 0)
{
string[--i] = '\0';
while (i != 0)
{
string[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", string);
}
return string;
}
int main (void)
{
char *buffer = reverse_string("tasdflkj");
if (buffer != 0)
{
printf("%s\n", buffer);
free(buffer);
}
return 0;
}
サンプル コードには、各書式文字列の末尾に改行が含まれていることに注意してください。弦の端がどこにあるかが分かりやすくなります。
main()
これは、関数を複数回呼び出した後でも、返された割り当てられたメモリが問題ないことを示す代替手段です (単純な引数の代わりに areverse_string()
を取るように変更されましたが、それ以外は変更されていません)。const char *
char *
int main (void)
{
const char *strings[4] =
{
"tasdflkj",
"amanaplanacanalpanama",
"tajikistan",
"ablewasiereisawelba",
};
char *reverse[4];
for (int i = 0; i < 4; i++)
{
reverse[i] = reverse_string(strings[i]);
if (reverse[i] != 0)
printf("[%s] reversed [%s]\n", strings[i], reverse[i]);
}
for (int i = 0; i < 4; i++)
{
printf("Still valid: %s\n", reverse[i]);
free(reverse[i]);
}
return 0;
}
また(このメモを私のメモに追加する前にpwnyが彼の回答で指摘したように)、文字列が null で終了していることを確認する必要があります。サンプル コードの問題をすぐに特定できない場合でも、ローカル文字列へのポインターを返すことは安全ではありません。これは、出力の最後のガベージを説明します。