🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

2698閲覧

C++ 関数にポインタを渡してnewする場合

ken_digi

総合スコア19

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/09/27 23:27

前提

C++を学習中です。
関数にintのポインタ型を渡してnewさせ、5を代入させたいとして、
初めにソースコード中SetAAA()のように試したのですがうまくいかず、
続いてSetBBB()のようにダブルポインタを渡して間接的にnewさせるとうまくいきました。
しかし、両者の違いがいまだによくわかりません。
なぜSetAAA()のような方法だと失敗するのか、教えていただきたいです。

ソースコード

C++

1#include <iostream> 2using namespace std; 3 4int* ttt; 5void SetAAA(int* aaa) { 6 aaa = new int; 7 *aaa = 5; 8} 9void SetBBB(int** bbb) { 10 *bbb = new int; 11 **bbb = 5; 12} 13 14int main() { 15 //SetAAA(ttt); だと失敗 16 SetBBB(&ttt); 17 cout << *ttt << endl; 18 19 return 0; 20}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

なぜSetAAA()のような方法だと失敗するのか、教えていただきたいです。

C++の引数は、特に指定しない場合値渡しなので、aaa = new intとしても、関数の外にその値は影響しません。つまり、*aaa = 5;の代入自体はできているのですが、肝心のポインタ値がどこにも伝わらない状態となります。

投稿2019/09/28 00:04

maisumakun

総合スコア145975

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ken_digi

2019/09/28 00:36

つまり、 ・aaa = new int; しても、メモリが確保されるのは「aaa」のみで、aaaは関数終了時にはポインタ型としての存在が消える ・よってtttのメモリ確保は行われず、0ポインタを指すまま という解釈で合っていますか?
guest

0

ベストアンサー

実際にどこでメモリが確保されるかを説明します。

ttt はグローバル変数なので 0 で初期化されます。
C++ なので ttt の値は nullptr です。


SettAAA(ttt); で関数 SetAAA を呼び出すとき、
引数である変数 aaa がメモリ上に確保されて、
そこに ttt の値である nullptr が格納されます。

aaa = new int; ですが、
new int で int のサイズの領域がメモリ上に確保されます。
この領域に変数名のような名前はありませんが、
メモリ上に領域が存在するので、そのアドレスはあります。
演算子 new はそのアドレスを値として返します。
その値の型は int * です。
aaa = により、aaa が持っていた nullptr は破壊され、
aaa には「new int で確保された領域のアドレス」が格納されます。

*aaa = 5; により、「new int で確保された領域」に 5 が格納されます。

関数 SetAAA から main に戻るとき、変数 aaa の領域は解放されます。
「new int で確保された領域」は解放されずに残っています。

ttt の値は nullptr のまま変わってはいないので、*ttt を参照すると失敗します。


SetBBB(&ttt); で関数 SetBBB を呼び出すとき、
引数である変数 bbb がメモリ上に確保されて、
そこに &ttt すなわち「ttt のアドレス」が格納されます。

*bbb = new int; ですが、
new int で int のサイズの領域がメモリ上に確保されます。
この領域に変数名のような名前はありませんが、
メモリ上に領域が存在するので、そのアドレスはあります。
演算子 new はそのアドレスを値として返します。
その値の型は int * です。
bbb の値は「ttt のアドレス」ですから、*bbb は変数 ttt です。
*bbb = により、ttt が持っていた nullptr は破壊され、
ttt には「new int で確保された領域のアドレス」が格納されます。

*bbb が変数 ttt なので、**bbb = 5; は *ttt = 5; と同じ意味になり、
「new int で確保された領域」に 5 が格納されます。

関数 SetBBB から main に戻るとき、変数 bbb の領域は解放されます。
「new int で確保された領域」は解放されずに残っています。

ttt の値は「new int で確保された領域のアドレス」なので、
*ttt の値は、「new int で確保された領域」の値 5 になります。

投稿2019/09/28 03:58

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ken_digi

2019/09/28 04:50

わざわざ長文で解説していただき、ありがとうございます。 SetAAA()の挙動は、いわば「aaa」のみのnewで、目的の「ttt」はメモリ確保されないということですね。 とても分かり易かったです!
kazuma-s

2019/09/28 05:07

ttt はグローバル変数ですから、ttt 自身のメモリ領域は確保されています。 「new で確保したメモリ領域のアドレス」が aaa には設定されるが、ttt には設定されない、ということです。
ken_digi

2019/09/28 06:30

ttt宣言(0ポインタ) ↓ aaa = new int; でメモリ確保、aaaに該当アドレスが格納 ↓ 関数終了でaaa破棄、しかしメモリ自体は確保 ↓ tttには該当アドレスが入らないので0のまま ということですか? また、グローバル変数は宣言のみでメモリ確保が行われるということですか? 長文失礼しますが、ご回答よろしくお願いします。
ken_digi

2019/09/28 06:48

ttt自体はメモリ確保されるけど、「指すアドレス」が0ポインタのまま、ということですね。
guest

0

宣言時にnew intされていないため、宣言時のtttには0が入っており、
&tttにはtttのアドレスが格納されています。
そのため、tttを引き渡すsetAAAではtttを引き渡すことができず(new intできない)、
&tttを引き渡すsetBBBでは、tttのポインタ経由でtttも操作(new int)することができます。

投稿2019/09/28 00:07

編集2019/09/28 00:45
gnbrganchan

総合スコア438

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/09/28 00:11

C++は本当に参照を引数として渡せます。このコードは「ダブルポインタ渡し」であって、「ポインタの参照渡し」ではないです。
gnbrganchan

2019/09/28 00:20

見間違えていました。修正します。
ken_digi

2019/09/28 00:52

なるほど。SetAAA()にてaaaをnewしても実際にメモリ確保されるのは「aaa」のみで、目的のtttには全く影響がないという事ですね。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問