a.i=b.iであればstrcpy_s(a.i,50,"ねこねこ");、strcpy_s(b.i,50,"ねこねこ");は同じアドレスのメモリに"ねこねこ"を格納することになります

ソーラー「では


今まで登場した


問題点を整理すると・・・」


マックス「何も問題点なんてないんじゃないか?」


ソーラー「大正解です


何も問題なんて~ぇ😊ないんです」



てんC「今までのお話は


とても単純で


オブジェクト宣言により生成される


オブジェクトaとオブジェクトb


の独立性は保たれる


つまり


オブジェクト宣言により生成される


オブジェクトaとオブジェクトb



それぞれ別のメモリを管理する


というお話でしたね😊」


マックス「??


なぜ


ここで


オブジェクト宣言により生成される


オブジェクトaとオブジェクトb



それぞれ別のメモリを管理する


という基本的な話になってくるんだ?


あたりまえすぎないか?


オブジェクトaとオブジェクトb



それぞれ別のメモリを管理するということに


何も問題はないじゃないか」



🌞    🌞    🌞    🌞    🌞    🌞    🌞



さて



クラスSuutitoMojiがあるとします。




クラスSuutitoMojiのクラス宣言は次のように設定されているとします」

👇


class SuutitoMoji{


public:


int x;


public:


char* i;


};


🌞    🌞    🌞    🌞    🌞    🌞    🌞



ソーラー「この


クラスSuutitoMojiを用いて


bのクラスSuutitoMoji型のオブジェクト宣言


SuutitoMoji b;



実行して


クラスSuutitoMoji型のオブジェクトbを生成したとします


その次に




      aのクラスSuutitoMoji型のオブジェクト宣言、


     クラスSuutitoMoji型のオブジェクトbによる初期化


           SuutitoMoji a=b;


を実行すれば


クラスSuutitoMoji型のオブジェクトbのメンバ変数


b.x

b.i



格納しているデータを


クラスSuutitoMoji型のオブジェクトaのメンバ変数


a.x

a.i


に代入して


クラスSuutitoMoji型のオブジェクトaを初期化することができます 」


てんC「


SuutitoMoji a=b;


が実行されると


普通に


クラスSuutitoMoji型のオブジェクトa

クラスSuutitoMoji型のオブジェクトb


によって初期化されますね😊


SuutitoMoji a=b;



実行しても


もちろん


💖SuutitoMojiaSuutitoMojib💖


クラスSuutitoMoji型のオブジェクトaとクラスSuutitoMoji型のオブジェクトbの独立性は保たれていて


クラスSuutitoMoji型のオブジェクトaとクラスSuutitoMoji型のオブジェクトbは


それぞれ独立したメモリを管理しています


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数


a.x

a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数


b.x

b.i



独立性は保たれているので


クラスSuutitoMoji型のオブジェクトaのメンバ変数


a.x

a.i


に格納されているデータを変更しても


クラスSuutitoMoji型のオブジェクトbのメンバ変数


b.x

b.i


に格納されているデータは変更されないのですね😊」



ソーラー「そう


これが


aのクラスSuutitoMoji型のオブジェクト宣言、初期化


SuutitoMoji a=b;


を実行したときの


クラスSuutitoMoji型のオブジェクトa

クラスSuutitoMoji型のオブジェクトbの状態です


そう


SuutitoMoji a=b;


が実行されても


  

        💖💖🌞必ず🌞💖



クラスSuutitoMoji型のオブジェクトa

クラスSuutitoMoji型のオブジェクトb


それぞれ独立したメモリを管理することになります」



ソーラー「さて



このクラスSuutitoMojiのように



クラスSuutitoMojiのメンバ関数宣言に


      🍅char*型のポインタ変数宣言🍅


            🍅char* i;🍅


が設定されている場合に


bのクラスSuutitoMoji型のオブジェクト宣言


SuutitoMoji b;



実行し


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


を生成したとします


b.xには


b.x=1;


を実行して


数値データ1を代入し


b.iには


(b.i=new char[50];


を実行して


動的にメモリ領域を確保し)


動的に確保したメモリ領域の先頭のメモリを格納します


初期化の完了ですね


次に


strcpy_s(b.i,50,"にゃこ");


を実行して


動的に確保したメモリ領域に


文字列データ


"にゃこ"


を格納したとします


さらに


クラスSuutitoMoji型のオブジェクトa

を生成し

クラスSuutitoMoji型のオブジェクトbで


初期化する命令文


SuutitoMoji a = b;


を実行したとします


この場合でも


クラスSuutitoMoji型のオブジェクトa

クラスSuutitoMoji型のオブジェクトb

の独立性は保たれます


すなわち


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.x



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x


は独立性が保たれ


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.x



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x


それぞれ別のメモリを管理します


さらに


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


も独立性が保たれ


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



それぞれ別のメモリを管理することになります



このとき


SuutitoMoji a = b;


が実行されているので


a.i=b.i


が実行されていますね


a.i=b.iにより


   クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


             と


   クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



ともに


             💖同じアドレス💖


を格納することになります


b.iには


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて動的に確保したメモリ領域の先頭のメモリのアドレス


を格納しているので


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iにも動的に確保したメモリ領域の先頭のメモリのアドレスが格納されることになります




     クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


             と


      クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



ともに


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて


動的に確保したメモリ領域の先頭のメモリのアドレス


を格納することになります


すこしだけいいかえると


     クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


             と


      クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



ともに



同じ


文字列データ"にゃこ"


を格納しているメモリ領域の先頭のメモリのアドレス


を格納することになります





このとき


strcpy_s関数を用いて


 クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に宛てて


つまり


(文字列データ"にゃこ"を格納している)動的に確保したメモリ領域に宛てて


文字列データ"ねこねこ"



格納してみたいと思います


動的に確保したメモリ領域に


格納されている文字列データ


"にゃこ"


の代わりに


"ねこねこ"



格納したいというわけです



そのときの命令文は


strcpy_s(a.i,50,"ねこねこ");


となります


strcpy_s(a.i,50,"ねこねこ");


が実行されても


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納している動的に確保したメモリ領域の先頭のメモリのアドレス番号



そのまま


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


に格納されたままで


変更されることはありません」


マックス「はいぃ? それはそうだろぉ


strcpy_s(a.i,50,"ねこねこ");



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域(動的に確保したメモリ領域)に


つまりイコール


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて動的に確保したメモリ領域に


文字列データ"ねこねこ"



格納する命令文だろう?


strcpy_s関数は


 クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号を


変更する命令文じゃないだろう


ふはははは


動的に確保したメモリ領域に


文字列データ"ねこねこ"


が格納されるときに


 クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号が


変更されるっていうのはありえないな」



ソーラー「もちろんその通りなんです


そして


SuutitoMoji a = b;


が実行されることにより


a.i=b.i


が実行されているので


       クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


             と


       クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



ともに同じアドレス番号


すなわち


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて


動的に確保したメモリ領域の先頭のメモリのアドレス番号


を格納することになります


つまり


strcpy_s(a.i,50,"ねこねこ");


が実行されると


動的に確保したメモリ領域に


文字列データ"ねこねこ"


が格納されることになるのですが


a.i

b.i


ともに動的に確保したメモリのアドレスを格納しているので


cout<<a.i<<"\n";


を実行しても


cout<<b.i<<"\n";


を実行しても


コマンドプロンプト画面に


文字列データ"ねこねこ"


が表示されることになります


なぜなら


cout<<a.i<<"\n";



a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納されている文字列データを


コマンドプロンプト画面に表示する命令文で


cout<<b.i<<"\n";



b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納されている文字列データを


コマンドプロンプト画面に表示する命令文で


a.iが格納しているアドレス番号



b.iが格納しているアドレス番号



           ともに同じ



    動的に確保したメモリのアドレス番号だからですね




さらに次に


クラスSuutitoMoji型のオブジェクトのメンバ変数b.iに宛てて


strcpy_s関数を用いた


strcpy_s(b.i,50,"にゃん");


が実行されると


動的に確保されたメモリ領域には


文字列データ


"にゃん"



格納されることになるのですが


a.i

b.i


ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納しているので


cout<<a.i<<"\n";


を実行しても


cout<<b.i<<"\n";


を実行しても


コマンドプロンプト画面に


文字列データ"にゃん"


が表示されることになります


このように


a.i

b.i


ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納しているので


a.iやb.iを用いて


strcpy_sを使って文字列データを動的に確保したメモリに格納した場合


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果は


必ず同じ動的に確保したメモリに格納された文字列が表示されることになるわけです



もちろん


この場合でも


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



独立性は


保たれています


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


に格納されているをアドレスを変更しても


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレスは変更されないし


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレスを変更しても


クラスSuutitoMoji型のオブジェクトbのメンバ変数a.i


に格納されているアドレスは変更されません




         めでたし  めでたし


             ちゃんこ、ちゃんこ


というわけです

        

ですが


strcpy_s(a.i,50,"ねこねこ");


が実行されると


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果が


ねこねこ

ねこねこ


strcpy_s(b.i,50,"にゃん");


が実行されると


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果が


にゃん

にゃん


となると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


は同じメモリにアクセスしているように見え


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


の独立性は


保たれていないようにみえるかもしれません


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


は同じメモリを管理しているようにみえるかもしれません


              


               が




もちろん


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


はそれぞれ別のメモリを管理しています


そのようにみえる原因は


strcpy_s(a.i,50,"ねこねこ");


が実行されるだけで


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果が


ともに同時に


等しく


ねこねこ


が表示されるように


変化してしまうからなんだね 」




おまけ


cout<<a.i<<"\n";

cout<<b.i<<"\n";



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレスを表示する命令文でなく


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレス番号のついたメモリを先頭とするメモリ領域に格納されている文字列データ



表示する命令文なんです


間違えやすいところです


                          solarplexussより



ですから


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレスが


ともに同じ動的に確保されたメモリ領域のアドレスなら


動的に確保されたメモリ領域に格納される文字列データが


strcpy_s関数によって


変更されると


そのたびに


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果も


一緒に


その動的に確保されたメモリ領域に格納された文字列データに


変更されるというわけです


そう


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


に格納されているアドレスがともに


同じ動的に確保されたメモリ領域の先頭のメモリのアドレスなので


動的に確保されたメモリ領域に格納されている文字列データが変更されると


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果も


一緒に


その動的に確保されたメモリ領域に格納された文字列データに


変更されるのですね




strcpy_s(a.i,50,"ねこねこ");



動的に確保されたメモリ領域に文字列データ


"ねこねこ”


を新たに格納する命令文です


ですから


strcpy_s(a.i,50,"ねこねこ");



が実行されて


動的に確保されたメモリ領域に


文字列データ


"ねこねこ”


が格納されることになると


cout<<a.i<<"\n";

cout<<b.i<<"\n";


の実行結果も同時に


ねこねこ

ねこねこ


になるというわけです」



ソーラー「はあ、はあ」



ソーラー「


ここで


今までの流れをあらわすプログラムを実行してみたいと思います


そのプログラムは次のようになります

👇

#include <iostream>


using namespace std;


class SuutitoMoji{


public:


int x;


public:


char* i;


};


int main() {


SuutitoMoji b;


b.x = 1;

b.i = new char[50];


strcpy_s(b.i,50, "にゃこ");


SuutitoMoji a = b;


strcpy_s(a.i, 50, "ねこねこ");


cout << a.i << "\n";

cout << b.i << "\n";


strcpy_s(b.i, 50, "にゃん");


cout << a.i << "\n";

cout << b.i << "\n";


return 0;

}



プログラムの実行結果


ねこねこ

ねこねこ

にゃん

にゃん


ソーラー「このプログラムでは


SuutitoMoji b;


b.x = 1;


により


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xに1が代入されています


そして


b.i = new char[50];


を実行することにより


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて


動的にメモリ領域を確保しています


このとき


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iには動的に確保したメモリ領域の先頭のメモリのアドレスが


代入されることになります


次に


strcpy_s(b.i,50, "にゃこ");


が実行されると


動的に確保されたメモリ領域に


文字列データ


"にゃこ"


が格納されることになります



この状態で


SuutitoMoji a = b;


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xには


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xの格納している


数値データ1が


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iには


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iの格納している


(動的に確保されたメモリ領域の先頭のメモリの)アドレスが


格納されることになります


この状態で


strcpy_s(a.i, 50, "ねこねこ");


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iの格納しているアドレス番号の付いたメモリを先頭とするメモリ領域にあてて


つまり


動的に確保したメモリ領域に



文字列データ


"ねこねこ"


は格納されることになります


cout << a.i << "\n";



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域


に格納されている文字列データを


コマンドプロンプト画面に表示する命令文



cout << b.i << "\n";



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に


格納されている文字列データを


コマンドプロンプト画面に表示する命令文です


SuutitoMoji b;


b.x = 1;

b.i = new char[50];


strcpy_s(b.i,50, "にゃこ");


のあと


SuutitoMoji a = b;


が実行されて


a.i=b.i


となっているので



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i



ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納することになり


cout << a.i << "\n";

cout << b.i << "\n";



等しく動的に確保されたメモリ領域に格納されている文字列データを


コマンドプロンプト画面に表示する命令文となります


cout << a.i << "\n";


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納された文字列データ


つまり


動的に確保されたメモリ領域に格納された文字列データ


"ねこねこ”


がコマンドプロンプト画面に表示され


cout << b.i << "\n";


が実行されると


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iが格納しているアドレスの付いたメモリを先頭とするメモリ領域


つまり


動的に確保されたメモリ領域


に格納された文字列データ


"ねこねこ”


がコマンドプロンプト画面に表示されることになります


同様に


次に


strcpy_s(b.i, 50, "にゃん");


が実行されると


cout << a.i << "\n";

cout << b.i << "\n";



実行結果は


にゃん

にゃん


になります


めでたし


めでたし


マックス「やったな ソーラー


あたりまえのこと~のような気がするが。。。


なんか よくわからんような気もするな


だが この解説の詳しさには驚いたぞ!」

  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る