関数は C++ でローカル変数エラーのアドレスを返します
 
スコープに基づいて、C および C++ の変数はローカル変数とグローバル変数に分けられます。 グローバル変数にはプログラムのどの部分からでもアクセスできますが、ローカル変数には同じことが当てはまりません。
したがって、さまざまな機能がコードに含まれている場合は、慎重に使用することが重要です。 そうしないと、返されたローカル変数のアドレスエラーが発生する可能性があります。
このエラーが発生する理由と修正方法について説明します。
関数は C++ でローカル変数エラーのアドレスを返す
function returns the address of the local variable エラーの理由と可能な修正を理解するには、ローカル変数がどのように機能するかを知る必要があります。 まずこれについて議論しましょう。
C++ におけるローカル変数の動作
ローカル変数は、関数内で定義され、その特定の関数の外では使用できない変数です。 つまり、定義された関数内にのみ存在し、プログラムの他の部分からアクセスすることはできません。
ここで非常に重要な情報があります。ローカル変数の寿命は、関数の実行が終了するとすぐに破棄されます。
この例を見てください。 ここで、変数 cost は関数 demo() 内で宣言されています。 したがって、その範囲はこの関数のみに限定されます。
main ブロック内で、このローカル変数にアクセスしようとするため、プログラムでエラーが発生します。
これは基本的に、ローカル変数がどのように機能するかです。
#include <iostream>
using namespace std;
void demo() {
  int cost = 5000;
  cout << "The variable cost is local to the demo function." << endl;
}
int main() {
  int cakes = 10;
  demo();
  cout << "Payable amount: " << cost;
}
出力:
In function 'int main()':
error: 'cost' was not declared in this scope
     13 |     cout << "Payable amount: " << cost;
        |                                   ^~~~
これで、スコープ外でローカル変数を使用することがどのように違法であるかがわかりました。 関数がローカル変数のアドレスを返すエラーが発生する理由について説明しましょう。
C++ のローカル変数と関数の詳細については、この ドキュメントを参照してください。
C++ でローカル変数のアドレスを返す関数の原因
関数はローカル変数のアドレスを返します エラーは通常、関数とローカル変数の操作中に発生します。 定義されたスコープ外のローカル変数にアクセスできないように、そのスコープ外のアドレスにもアクセスできません。
このように見てください。 定義されたスコープ外のローカル変数にアクセスしようとすると、上記の例に示すように、変数がこのスコープで宣言されていませんというエラーが発生します。
ただし、定義されたスコープ外のローカル変数のアドレスにアクセスしようとすると、関数はローカル変数のアドレスを返しますというエラーが発生します。
これがなぜ起こるかです。
関数の実行が完了すると、ローカル変数が破棄されることがわかっています。 これは、ローカル変数のアドレスを返すポインターが存在しないオブジェクトを指していることを意味します。
ローカル変数へのポインターは、ローカル変数が存在する関数の外に出ることはできません。 しかし、これが発生すると、ポインターがダングリング ポインターに変化したと言えます。したがって、関数がローカル変数のアドレスを返すというエラーが発生します。
このエラーはさまざまな場合に発生する可能性があります。 それらについて1つずつ説明しましょう。
関数がローカル変数のアドレスを返す例 C++ でエラーが発生する
このようなすべてのコードが関数がローカル変数のアドレスを返すエラーに遭遇する原因は、上記で説明したものと同じですが、いくつかの例を詳しく見てみましょう。
関数はローカル変数へのポインタを返す
以下のコードを見てください。 demo() という関数があります。これは 2つの整数値を取り、それらを加算します。
この関数は合計を変数 cost に格納し、この変数のアドレスを返します。 しかし、このコードを実行すると、返されたローカル変数のアドレスエラーが発生します。
ここで 2つのことに注意してください。
- 変数 costは関数demo()内で定義されます。 したがって、その範囲はこの関数のみに限定されます。 ローカル変数です。
- returnステートメントは、ローカル変数- costのアドレスを持つポインターを返します。
関数 demo() が実行を終了するとすぐに、その中に存在するローカル変数 cost も破棄されることがわかっています。 これは、以前は変数 cost のアドレスを指していたポインターが、もはや所有していないメモリ内の場所を指し始めることを意味します。
したがって、このエラーが発生します。
#include <iostream>
using namespace std;
int* demo(int cherry, int pie) {
  int cost = cherry + pie;
  return &cost;
}
int main() { int* ans = demo(100, 20); }
出力:
In function 'int* demo(int, int)':
warning: address of local variable 'cost' returned [-Werturn-local-addr]
    7 |    return &cost;
      |           ^~~~~
note: declared here
    6 |    int cost = cherry + pie;
      |        ^~~~
これを修正する方法を見てみましょう。 問題は、戻りアドレスがローカル変数のアドレスであることです。 したがって、動的メモリ割り当てはこれを解決するのに役立ちます。
main ブロック内で、変数 cost を動的に定義し、メモリを割り当てます。 次に、この変数をパラメーターとして demo() 関数に渡します。
#include <iostream>
using namespace std;
int* demo(int cherry, int pie, int* cost) {
  *cost = cherry + pie;
  return cost;
}
int main() {
  int* cost = new int;
  cost = demo(100, 20, cost);
  cout << "The total is stored at address: " << cost;
}
出力:
The total is stored at address: 0x55c7997a7eb0
このコードを実行すると、今度は正しい出力が得られます。 これは、変数 cost が demo() 関数の外で宣言されているため、もはやローカル変数ではないためです。
関数は、スコープがローカルである文字列を返す
次のコード スニペットを見てください。 ここでは、ユーザーからの入力として名前を受け取り、checkname() 関数を使用して有効かどうかを確認します。
checkname() 関数内で、fullname という文字列を定義し、チェック条件に合格した場合にそれを返します。 しかし、コードは function returns the address of the local variable エラーに遭遇します。
これがなぜ起こるかです。
スコープが checkname() 関数に限定されている fullname という文字列があります。 また、文字列は、渡される前にポインターに縮小される配列のようなものです。
main ブロックに戻ると、コントロールがその関数から移動したため、関数のローカル変数は破棄されます。
これが、エラーが発生する理由です。
#include <cstring>
#include <iostream>
using namespace std;
char* checkname() {
  char fullname[20];
  //....
  //......
  //....
  if ((strlen(fullname)) >= 4 && (strlen(fullname)) < 30) {
    return fullname;
  } else {
    return NULL;
  }
}
int main(void) {
  char name[20];
  cout << "Enter name:" << endl;
  name = checkname();
}
出力:
warning: address of local variable 'fullname' returned [-Wreturn-local-addr]
これを修正するには、データを返す代わりに、次のように関数に渡します。
#include <cstring>
#include <iostream>
using namespace std;
void checkname(char *fullname) {
  if ((strlen(fullname)) >= 4 && (strlen(fullname)) < 30) {
    cout << "Success";
  } else {
    cout << "In else block";
  }
}
int main(void) {
  char name[20];
  cout << "Enter name:" << endl;
  checkname(name);
}
出力:
Enter name:
In else block
今回はコードが正常に実行され、何も入力していないので、else ブロック内に入ります。
これで問題は解決しますが、より堅牢な解決策は、次のようにメモリを変数 fullname に動的に割り当てることです。
char *fullname = malloc(sizeof(char) * the_size);
.......return fullname;
メモリを動的に割り当てる場合、プログラム全体の実行まで、有効期間が有効なヒープからメモリが割り当てられます。 したがって、ここで変数 fullname を返すと、malloc によって定義されたアドレスが取得され、コードは正常に実行されます。
また、完了したメモリを解放することは、メモリ リークを回避するための良い方法です。
まとめ
この記事では、C++ での 関数がローカル変数のアドレスを返す エラーについて説明しました。 ローカル変数がどのように動作するか、およびそれらのスコープ外にアクセスしようとすることがどのように違法であるかを学びました。
このエラーの理由と、いくつかのユースケースを使用して考えられる解決策を確認しました。