Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

C++

C++の動的メモリ割当と静的メモリ割当の違いについて

投稿日:2021年10月18日 更新日:

 

<目次>

(1) C++の動的メモリ割当と静的メモリ割当の違いについて
 (1-1) 静的メモリ割当てとは?
 (1-2) 動的メモリとは?
 (1-3) 動的メモリの割当て
 (1-4) 「静的メモリ割当て」と「動的メモリ割当て」の違い

(1) C++の動的メモリ割当と静的メモリ割当の違いについて

(1-1) 静的メモリ割当てとは?

静的メモリ割当て(&解放)は「確保する領域が固定長」のメモリ割当て(&解放)の事で、プログラムの実行前(コンパイル時)に割当て(&解放)され、「スタックメモリ」とも呼ばれます。
以下の例を見てみます。4つの変数「a1」「b1」「c1」「d1」があり、これらはコンパイル時にコンパイラによって「どれだけメモリが必要か?」が計算され、決められたアドレスに格納されます(コンパイル時の割当て&解放のハンドリング)。
 
(サンプル)
#include <iostream>
using namespace std;
int main()
{
    //# 静的メモリ割当て
    int a1;
    int b1[10];
    double d1;
    char c1;
    
    return 0;
}
 

(1-2) 動的メモリとは?

通常、プログラムのメモリは前述の「静的メモリ割当て」によりコンパイル時に変数の定義により確保&解放されますが、場合によっては実行時にメモリを確保&解放したいケースがあります。例えば、必要なメモリ量がユーザの入力値によって決まる場合などです。
 
このようなケースでは実行時に動的にメモリを割り当てる必要がありますが、C++では「new」や「delete」演算子を用いて行います(プログラマがコードの中で、newやdeleteを使って割当てや解放を行う)。
 

(1-3) 動的メモリの割当て

(1-3-1) 割当て方法

動的メモリの割当ては「new」演算子を用いて行われます。newの後にはデータ型を指定し、もし1つ以上の要素が必要な場合には[N]で要素数を指定します(Nは整数)。また重要な点として、戻り値は確保したメモリの最初の要素のアドレスを指す「ポインタ」(⇒★C++_ポインタ_とは)になります。なので、左辺はポインタ(「int hoge」ではなく「int * hoge」)にります。
(例1)要素が1つのメモリを割当て
int * hoge1 = new int;
(例2)要素が5つのメモリを割当て
int * hoge2 = new int [5];
(例2)の場合は、int型の要素を動的に5つ連続して確保し、その内の最初の1要素目へのポインタを返却してhogeに割り当てています。
 
(図111)

(1-3-2) 要素へのアクセス(先頭)

この時、1要素目へのポインタである「hoge」にアクセスするには、以下の2通りで記述できます。
//# ポインタ「*hoge」へのアクセス方法1
hoge[0]
//# ポインタ「*hoge」へのアクセス方法2
*hoge
簡単なサンプルプログラムで動きを確認します。
 
(サンプル)
#include <iostream>
using namespace std;
int main(void){
    
    //# ポインタ「*n1p」を定義
    int n1 = 10;
    int *n1p = &n1;

    //# ポインタ「*n2p」を定義    
    int *n2p = new int;
    n2p[0] = 10;

    //# 2通りの方法でアクセス
    cout << "アクセス方法1:" << *n2p << " アドレス:" << n2p<< endl;
    cout << "アクセス方法2:" << n2p[0] << " アドレス:" << &n2p[0] << endl;
    
    delete []n1p;
    delete []n2p;
}
(図121)

目次にもどる

(1-3-2) 要素へのアクセス(2番目以降)

同様に2つ目の要素にアクセスする際には次のように記述できます。
//# ポインタ「*hoge」へのアクセス方法2
hoge[1]
//# ポインタ「*hoge」へのアクセス方法2
*(hoge+1)
こちらも簡単なサンプルで動きを確認します。
 
(サンプル)
#include <iostream>
using namespace std;
int main(void){

    //# ポインタ「*n2p」を定義    
    int *n2p = new int[5];
    n2p[0] = 10;
    n2p[1] = 25;

    //# 2通りの方法でアクセス
    cout << "要素2へのアクセス方法1:" << *(n2p+1) << " 要素2のアドレス:" << (n2p+1)<< endl;
    cout << "要素2へのアクセス方法2:" << n2p[1] << " 要素2のアドレス:" << &n2p[1] << endl;

    delete []n2p;
}
(図122)

目次にもどる

(1-4) 「静的メモリ割当て」と「動的メモリ割当て」の違い

静的メモリの割当てと動的メモリ割当ての大きな違いとして、「配列の大きさを動的に変えられるか?」が挙げられます。静的な配列は大きさを固定長で指定するのに対して、動的な配列は大きさを変数で指定し、実行時に動的に変える事ができます。
 
動的に割り当てるメモリは、システムのメモリヒープ(動的割当てに使われる領域)より割り当てられますが、メモリが逼迫している状況下では、必ず割当てが正常に行われる保証はありません。
 
もしもメモリの割当てが正常に実施できない場合、例外(bad_alloc)がthrowされるため、それをcatchする事により検知する事ができます。
 
(表)両者の違い
●観点 ●静的メモリ割当て ●動的メモリ割当て
差異①
タイミング
プログラム実行前(コンパイル時)に割当て プログラム実行中に割当て
差異②
ポインタ要否
割当てを行うにはポインタは不要(「int n1p[5];」のように宣言可能) 割当てを行うにはポインタが必要(「int *n2p = new int[5];」のように宣言する必要あり)
差異③
処理速度
動的割当てより、少し速い 静的割当てより、少し遅い
差異④
メモリ使用量
動的割当てより、多く必要 静的割当てより、少なく済む

●差異②/差異④の確認

差異②/差異④の確認のための簡単なプログラムをご紹介します。静的割当ての方はポインタなしでメモリを確保しているのに対して、動的の方はポインタを使っています(ポインタなしだとエラーになります)。
 
(サンプル)
#include <iostream>
using namespace std;
int main(void){


    //# 静的メモリ割当て 
    //# ポインタなしで割当て可能
    int n1p[5];
    n1p[0] = 9999;
    cout << "n1pの要素1:" << n1p[0] << " サイズ:" << sizeof(n1p) << endl;
    
    //# 動的メモリ割当て
    //# 動的割当てにはポインタが必要
    int *n2p = new int[5];
    n2p[0] = 8888;
    cout << "n2pの要素1:" << n2p[0] << " サイズ:" << sizeof(n2p) << endl;
    
}
 
(図131)

目次にもどる

Adsense審査用広告コード


Adsense審査用広告コード


-C++

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

C++のtime関数とlocaltime関数の違いについて

  <目次> (1) C++のtime関数とlocaltime関数の違いについて  (1-1) C++のlocaltime関数の概要とサンプル  (1-2) C++のtime関数の概要とサン …

no image

C++で「error: cannot initialize a variable of type ‘const unsigned char’ with an lvalue of type ‘const char [x]’」が発生した時の原因と対処

<目次> (1) C++で「error: cannot initialize a variable of type ‘const unsigned char’ with an …

C++のfork関数の構文や使い方について

  <目次> (1) C++のfork関数の構文や使い方について  (1-1) fork()関数とは?概要や目的  (1-2) fork()関数の構文  (1-3) fork()関数のサンプ …

Valgrindとは?使い方や概要をご紹介(メモリリーク検知ツール)

  <目次> (1) Valgrindとは?使い方や概要をご紹介(メモリリーク検知ツール)  (1-1) Valgrindとは?  (1-2) Valgrindの導入方法  (1-3) Va …

Valgrindで行番号を表示させる方法

  <目次> (1) Valgrindで行番号を表示させる方法  (1-1) 行番号を表示させる方法  (1-2) (参考)「-g」オプションについて (1) Valgrindで行番号を表示 …

  • English (United States)
  • 日本語
Top