Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

CおよびC++における可変長配列(VLA)の徹底解説


本記事では、CおよびC++における可変長配列(Variable Length Array:VLA)について詳しく解説します。可変長配列を利用すると、実行時にサイズが決まる自動配列(スタック上の配列)を柔軟に確保できます。

C99での可変長配列のサポート

C言語では、C99規格以降、可変長配列が正式にサポートされており、次のように引数で渡された値をもとに配列サイズを指定できます。

void make_arr(int n){
    int array[n];
}
int main(){
    make_arr(10);
}

一方、C++の標準規格では(C++11まで)、可変長配列という概念は存在しませんでした。C++11規格では配列サイズを定数式(constant-expression)で指定する必要があるため、上記のコードはC++11以前の環境では有効なコードとは言えません。C++14では配列サイズが「単純な式」として扱われるようになりましたが、それでも可変長配列は標準機能として採用されていません。

なお、GCCなどの一部のコンパイラでは拡張機能としてVLAが利用できる場合がありますが、移植性を重視するなら標準規格に依存しない設計が推奨されます。

実装例:長さ0の配列メンバーによる代替手法

以下のサンプルコードでは、クラスの末尾に長さ0の配列メンバー(フレキシブル配列メンバーに相当するテクニック)を配置し、実行時に名前の長さが異なる従業員データを動的に管理する方法を示しています。

#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
class employee {
    public:
        int id;
        int name_length;
        int struct_size;
        char emp_name[0];
};
employee *make_emp(struct employee *e, int id, char arr[]) {
    e = new employee();
    e->id = id;
    e->name_length = strlen(arr);
    strcpy(e->emp_name, arr);
    e->struct_size=( sizeof(*e) + sizeof(char)*strlen(e->emp_name) );
    return e;
}
void disp_emp(struct employee *e) {
    cout << "Emp Id:" << e->id << endl;
    cout << "Emp Name:" << e->emp_name << endl;
    cout << "Name Length:" << e->name_length << endl;
    cout << "Allocated:" << e->struct_size << endl;
    cout <<"---------------------------------------" << endl;
}
int main() {
    employee *e1, *e2;
    e1=make_emp(e1, 101, "Jayanta Das");
    e2=make_emp(e2, 201, "Tushar Dey");
    disp_emp(e1);
    disp_emp(e2);
    cout << "Size of student: " << sizeof(employee) << endl;
    cout << "Size of student pointer: " << sizeof(e1);
}

出力結果

Emp Id:101
Emp Name:Jayanta Das
Name Length:11
Allocated:23
---------------------------------------
Emp Id:201
Emp Name:Tushar Dey
Name Length:10
Allocated:22
---------------------------------------
Size of student: 12
Size of student pointer: 8

解説のポイント

構造体やクラスの末尾に長さ0の配列を配置することで、実際の文字列の長さに応じた柔軟なメモリ管理が可能になります。ただし、この手法には実装依存の側面がある点に注意が必要です。現代のC++では、std::vectorstd::string といった標準ライブラリのコンテナを活用する方が安全性が高く、一般的に推奨されています。

  1. C++で円と長方形の重なりを判定するアルゴリズム

    問題の概要円を (radius, xc, yc) という形式で表します。ここで (xc, yc) は円の中心座標です。同様に、軸に平行な長方形(軸平行境界ボックス)を (x1, y1, x2, y2) という形式で表し、(x1, y1) が左下隅の座標、(x2, y2) が右上隅の座標とします。このとき、円と長方形が互いに重なっているかどうかを判定する必要があります。たとえば、次のような入力が与えられた場合を考えてみましょう。この場合、出力は true(重なりあり)となります。解決のアプローチこの問題を解く鍵は、「長方形の中で円の中心に最も近い点」を見つけることです。その点と円の中心との距離が

  2. C++で解くドミノとトロミノを使ったタイル敷き詰め問題(2×Nボード)

    問題の概要本記事では、「ドミノ」と「トロミノ」という2種類の形状を使ったタイル敷き詰め(タイリング)問題をC++で解く方法を解説します。これらのピースは、以下のように回転させて使用することができます。タイリングでは、盤面上のすべてのマスを必ずタイルで覆わなければなりません。また、2つのタイリング方法は、盤上の4方向に隣接する2つのセルにおいて、片方のタイリングだけがその両方のマスを同じタイルで占有している場合に限り「異なる」とみなされます。入力と出力の例整数Nが与えられたとき、2×Nのボードを敷き詰める方法が何通りあるかを求めます。例えば、入力が3の場合、出力は5となります。敷き詰め方は以下の