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

なぜC++ではmalloc()の戻り値に明示的なキャストが必要なのに、C言語では不要なのか?

はじめに:両言語の決定的な違い

C言語では、voidポインタからオブジェクトポインタ型への暗黙的な変換が自動的に行われます。C89標準においてmalloc()関数はvoid*を返すため、その戻り値は任意のポインタ変数にそのまま代入でき、明示的なキャストは不要です(なお、それより前の初期のC言語ではchar*を返していました)。

一方、C++では型安全性を高めるという設計思想により、void*から他のポインタ型への暗黙的な変換が禁止されています。このため、C++でmalloc()を使用する場合は、戻り値を目的のポインタ型へ明示的にキャストしなければなりません。

C言語でのメモリ確保の構文

pointer_name = malloc(size);

各要素の意味は次の通りです。

  • pointer_name … ポインタに付ける任意の名前。
  • size … 確保するメモリのサイズ(バイト単位)。

C言語におけるmalloc()の使用例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n = 4, i, *p, s = 0;
    p = malloc(n * sizeof(int));
    if(p == NULL) {
        printf("\nError! memory not allocated.");
        exit(0);
    }
    printf("\nEnter elements of array : ");
    for(i = 0; i < n; ++i) {
        scanf("%d", p + i);
        s += *(p + i);
    }
    printf("\nSum : %d", s);
    return 0;
}

実行結果

Enter elements of array : 2 28 12 32
Sum : 74

上記のC言語の例では、仮に明示的なキャスト(int*)を追加してもエラーにはなりません。つまりC言語では、キャストの有無にかかわらずプログラムは正常にコンパイル・動作します。

C++でのメモリ確保の構文

pointer_name = (cast-type*) malloc(size);

各要素の意味は次の通りです。

  • pointer_name … ポインタに付ける任意の名前。
  • cast-typemalloc()で確保したメモリをキャストしたいデータ型。
  • size … 確保するメモリのサイズ(バイト単位)。

C++におけるmalloc()の使用例

#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
    int n = 4, i, *p, s = 0;
    p = (int *)malloc(n * sizeof(int));
    if(p == NULL) {
        cout << "\nError! memory not allocated.";
        exit(0);
    }
    cout << "\nEnter elements of array : ";
    for(i = 0; i < n; ++i) {
        cin >> *(p + i);
        s += *(p + i);
    }
    cout << "\nSum : " << s;
    return 0;
}

実行結果

Enter elements of array : 28 65 3 8
Sum : 104

上記のC++の例で、明示的なキャスト(int *)を省略すると、プログラムは次のようなコンパイルエラーを出力します。

error: invalid conversion from ‘void*’ to ‘int*’ [-fpermissive]
p = malloc(n * sizeof(int));

まとめ

  • C言語: void*からオブジェクトポインタ型への暗黙的な変換が許可されているため、キャストは不要(書いても問題なし)。
  • C++: 型安全性の観点からvoid*からの暗黙的な変換が禁止されており、明示的なキャストが必須。

補足として、現代のC++ではnew/delete演算子やスマートポインタ(std::unique_ptrなど)を使用することで、キャスト不要かつ型安全な動的メモリ管理が可能です。新規のC++コードでは、生のmalloc()よりもこれらの機能を使うことが強く推奨されています。

  1. C++でピラミッドの体積を計算するプログラムの作り方|底面の形状別の公式と実装例

    ピラミッドの底面の種類に応じた辺の長さが与えられたとき、そのピラミッドの体積を計算するのが本記事のテーマです。 ピラミッドとは、外側の面がすべて三角形で構成され、それらが共通の一点(頂点)で交わることで鋭い角を形成する3次元図形です。ピラミッドの体積は、底面がどのような形状であるかによって異なります。 ピラミッドの底面にはさまざまな種類があり、代表的なものは以下の通りです。 底面の形状別の体積の求め方 三角形の底面(三角錐) 底面が三角形の場合、ピラミッドの体積は次の公式で求められます。 体積 = (1/6) × a × b × h 正方形の底面(四角錐) 底面が正方形の場合、ピラミッドの体

  2. C++で学ぶクイックソート(QuickSort)の仕組みと実装方法

    クイックソートとはクイックソート(Quicksort)は、比較に基づいて未ソートのリスト(配列)を並べ替えるソートアルゴリズムの一つです。「パーティション交換ソート(partition exchange sort)」とも呼ばれます。クイックソートは安定ソートではありません。これは、等しい値を持つ要素同士の相対的な順序が保持されないためです。ただし、配列に対してごくわずかな追加メモリだけで動作するため、メモリ効率に優れています。選択ソートと非常に似ていますが、常に最悪のパーティションを選んでしまうわけではない点が異なり、より洗練された形の選択ソートと捉えることもできます。クイックソートは最も効率