メインコンテンツまでスキップ

言語の違い

プログラミング言語には、低レベル言語や高レベル言語などの分類があり、メモリ管理や書き方・用途・できること・できないことに違いがあります。

低レベル・高レベルの意味について



以下で、C、C++、Java、C#、JavaScript、Python、Dartなどの主要な言語を比較して解説します。



1. C

  • レベル: 低レベル寄りの中級レベル言語
  • メモリ管理: 手動管理。mallocfree を使用してメモリを明示的に割り当て・解放する。ポインタ操作による直接的なメモリ操作が可能。
  • 書き方: 非常に簡潔で、ハードウェアに近い処理ができる。シンプルな構造で直接的な処理を記述することが多い。

例:

#include <stdlib.h>  // mallocとfreeのために必要なヘッダーをインクルード

int main() {
int *p = malloc(sizeof(int));// メモリを動的に確保する(int型1つ分のサイズを確保)
*p = 10;// 確保したメモリに10を代入
free(p);// 確保したメモリを解放する
return 0;// 正常終了を示すために0を返す
}
  • できること: オペレーティングシステム、デバイスドライバ、組み込みシステムなど、低レベルのハードウェア制御が可能。
  • できないこと: 高レベルの抽象化された操作が不便。大規模開発ではコードの複雑さが増し、手動メモリ管理が面倒になる。


2. C++

  • レベル: 中間レベル言語(低レベル言語と高レベル言語の中間)
  • メモリ管理: 手動と自動の両方が可能。newdelete による手動メモリ管理に加え、スマートポインタなどの自動メモリ管理機能もある。
  • 書き方: Cの拡張版であり、オブジェクト指向プログラミングが可能。テンプレート、例外処理、標準ライブラリなどの高度な機能も提供。

例:

#include <iostream>

int main() {
int* p = new int(10);// ヒープ領域にint型のメモリを確保し、値10を初期化
delete p;// 確保したメモリを解放
return 0;// 正常終了を示すために0を返す
}
  • できること: Cに加えて、ゲーム開発、アプリケーションソフトウェア、ハードウェア制御など幅広い領域で使用される。
  • できないこと: 自動ガベージコレクションがなく、メモリリークの管理が困難な場合がある。コードの複雑化が進む場合がある。


3. Java

  • レベル: 高レベル言語
  • メモリ管理: 自動管理。ガベージコレクション(GC)により不要になったオブジェクトを自動的に解放。
  • 書き方: オブジェクト指向言語として設計され、コードが読みやすく、強力な標準ライブラリがある。クラスベースで、ほとんどのものがオブジェクトとして扱われる。

例:

public class Main {
public static void main(String[] args) {
// Integerクラスのオブジェクトを新規に生成しています。
// ここで "new Integer(10)" は、ヒープ領域に数値10を持つIntegerオブジェクトを作成します。
Integer num = new Integer(10);

// しかし、Javaでは、オートボクシングという機能により
// "new Integer(10)" の代わりに、単に "Integer num = 10;" と書けます。
// これは、基本データ型の値(int型の10)が自動的にIntegerオブジェクトに変換されるためです。
// そのため、"new Integer(10)" を使うケースは今ではほとんどなく、非推奨となっています。

// メモリ管理:
// Javaにはガベージコレクタ(GC)があるため、C++のように手動でdeleteを行う必要はありません。
// num変数がスコープを抜けた時点や不要になった時点で、GCがこのオブジェクトを検出し、
// メモリを自動で解放してくれます。
}
}

  • できること: クロスプラットフォームで動作し、エンタープライズ向けのシステム開発、Androidアプリ、サーバーアプリケーションなど幅広い用途に使用される。
  • できないこと: システムの深部にアクセスする低レベル操作は難しい。パフォーマンスがCやC++に劣ることがある。


スタックとヒープについて



4. C#

  • レベル: 高レベル言語
  • メモリ管理: 自動管理。ガベージコレクション(GC)を使用して不要なメモリを自動的に解放する。
  • 書き方: Javaに似たオブジェクト指向言語で、Microsoft .NETフレームワークと密接に統合されている。簡潔で強力な構文を持ち、幅広い用途に適用可能。

例:

using System;

class Program {
static void Main() {
// ここでは、int型の変数numを宣言し、値10を代入しています。
int num = 10;

// intはC#の基本型(値型)であり、スタックメモリに格納されます。
// ヒープではなく、スタックに格納されるため、特にメモリ管理の心配はありません。
// num変数がスコープを抜ける(このMainメソッドが終了する)と、スタックメモリから自動的に解放されます。

// C#では、メモリ管理は基本的にガベージコレクタ(GC)が自動で行います。
// 基本型(int, floatなど)はスタックに置かれますが、オブジェクト型(クラスなどのインスタンス)は
// ヒープに置かれ、GCが不要になったタイミングで自動解放します。
}
}

  • できること: デスクトップアプリケーション、Webアプリケーション、ゲーム開発(Unity)、エンタープライズシステムなどで広く使用。
  • できないこと: 基本的にWindowsプラットフォーム向けに設計されているため、特定の低レベルシステム操作は他の言語に劣る。

例:

using System;
using System.Collections.Generic;

class Task {
public string Name { get; set; }
public bool IsCompleted { get; private set; }

public Task(string name) {
Name = name;
IsCompleted = false;
}

public void Complete() {
IsCompleted = true;
Console.WriteLine($"タスク '{Name}' が完了しました。");
}

public override string ToString() {
return $"{Name} - {(IsCompleted ? "完了" : "未完了")}";
}
}

class Program {
static void Main() {
List<Task> tasks = new List<Task>();
string command;

Console.WriteLine("タスク管理アプリにようこそ!");

do {
Console.WriteLine("\nコマンドを入力してください:");
Console.WriteLine("1: タスクを追加する");
Console.WriteLine("2: タスクを完了する");
Console.WriteLine("3: タスクを表示する");
Console.WriteLine("4: 終了する");
command = Console.ReadLine();

switch (command) {
case "1":
Console.Write("追加するタスクの名前を入力してください: ");
string taskName = Console.ReadLine();
tasks.Add(new Task(taskName));
Console.WriteLine($"タスク '{taskName}' を追加しました。");
break;

case "2":
Console.Write("完了するタスクのインデックスを入力してください (0から始まる番号): ");
if (int.TryParse(Console.ReadLine(), out int index) && index >= 0 && index < tasks.Count) {
tasks[index].Complete();
} else {
Console.WriteLine("無効なインデックスです。");
}
break;

case "3":
Console.WriteLine("\nタスクリスト:");
for (int i = 0; i < tasks.Count; i++) {
Console.WriteLine($"{i}: {tasks[i]}");
}
break;

case "4":
Console.WriteLine("アプリを終了します。");
break;

default:
Console.WriteLine("無効なコマンドです。");
break;
}
} while (command != "4");
}
}

C#_実行例





・unityでの使用例

ScoreManager,cs

using UnityEngine;
using UnityEngine.UI;

public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance; // シングルトンインスタンス
public int Score { get; private set; } = 0; // スコア
public Text scoreText; // UIテキストオブジェクト

private void Awake()
{
// シングルトンの実装
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject); // シーンをまたいでオブジェクトを保持
}
else
{
Destroy(gameObject); // 既に存在する場合は削除
}
}

// スコアを加算するメソッド
public void AddScore(int points)
{
Score += points;
UpdateScoreText();
}

// スコアテキストを更新するメソッド
private void UpdateScoreText()
{
scoreText.text = "Score: " + Score;
}
}



PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour
{
private void Update()
{
// スペースキーを押したときにスコアを加算
if (Input.GetKeyDown(KeyCode.Space))
{
ScoreManager.Instance.AddScore(10); // スコアを10加算
}
}
}




5. JavaScript

  • レベル: 高レベル言語
  • メモリ管理: 自動管理。ガベージコレクション(GC)を使用してメモリを管理する。
  • 書き方: Webブラウザで動作するスクリプト言語であり、オブジェクト指向や関数型プログラミングの要素を持つ。簡単に動的なWebページを作成できる。

例:

let num = 10;
console.log(num);
  • できること: Webアプリケーション、クライアントサイド、サーバーサイド(Node.js)など広範な用途に対応。リアルタイムのWeb開発に適している。
  • できないこと: 低レベルのハードウェア制御は困難で、メモリ管理のカスタマイズもできない。

例:


function createObject() {
// スタックにローカル変数が格納される
const localConstant = "I am constant"; // スタックに格納され、再代入不可
let localVariable = 10; // スタックに格納され、再代入可能

// ヒープにオブジェクトを作成
const myObject = {
message: "I am an object",
value: 42
}; // `const` なので、プロパティの変更は可能だが、再代入は不可

console.log(localConstant); // スタックから値を取得
console.log(localVariable); // スタックから値を取得
console.log(myObject.message); // ヒープからオブジェクトのプロパティを取得

// `let`で宣言した変数の再代入
localVariable += 5;
console.log("Updated localVariable:", localVariable); // 15 が出力される

// オブジェクトのプロパティを更新
myObject.value += 10;
console.log("Updated myObject.value:", myObject.value); // 52 が出力される

// myObjectの参照を返す
return myObject;
}

// createObjectが呼ばれ、ローカル変数がスタックに追加される
const obj = createObject();
console.log(obj.value); // ヒープに格納されたオブジェクトのプロパティを参照(52 が出力される)




htmlと一緒に使った例:

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>タスク管理アプリ</title>
<style>
body { font-family: Arial, sans-serif; }
ul { list-style-type: none; padding: 0; }
li { padding: 8px; margin: 4px 0; background-color: #f0f0f0; }
button { margin-left: 10px; }
</style>
</head>
<body>
<h1>タスク管理アプリ</h1>
<input type="text" id="taskInput" placeholder="新しいタスクを追加">
<button id="addTaskBtn">タスクを追加</button>

<h2>タスクリスト</h2>
<ul id="taskList"></ul>

<script>
// タスクリストを保持する配列
let tasks = [];

// タスクを追加する関数
function addTask() {
const input = document.getElementById('taskInput');
const task = input.value.trim();//文字列の前後にある空白(スペース、タブ、改行など)を取り除く

if (task) {
// タスクを配列に追加
tasks.push(task);
input.value = ''; // 入力フィールドをクリア
renderTasks(); // タスクリストを再描画
} else {
alert('タスクを入力してください。');
}
}

// タスクリストを描画する関数
function renderTasks() {
const taskList = document.getElementById('taskList');
taskList.innerHTML = ''; // 既存のリストをクリア

// タスクをリストに追加
tasks.forEach((task, index) => {
const li = document.createElement('li');
li.textContent = task;

// 削除ボタンを作成
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '削除';
deleteBtn.onclick = () => deleteTask(index);

li.appendChild(deleteBtn);
taskList.appendChild(li);
});
}

// タスクを削除する関数
function deleteTask(index) {
tasks.splice(index, 1); // 配列からタスクを削除
renderTasks(); // タスクリストを再描画
}

// ボタンのクリックイベントを設定
document.getElementById('addTaskBtn').addEventListener('click', addTask);
</script>
</body>
</html>





6. Python

  • レベル: 高レベル言語
  • メモリ管理: 自動管理。ガベージコレクション(GC)が自動的に不要なメモリを解放する。
  • 書き方: シンプルで読みやすい構文が特徴。インデントでブロックを表すため、コードの可読性が高い。オブジェクト指向や関数型プログラミングもサポート。例:
    num = 10
    print(num)
  • できること: データサイエンス、AI/機械学習、Web開発、スクリプト言語として幅広く使用される。高水準のライブラリを利用して迅速に開発できる。
  • できないこと: パフォーマンスはCやC++に劣り、低レベルのハードウェア操作は不得意。

例:

class Counter:
def __init__(self):
self._count = 0 # 初期カウント値を0に設定

def increment(self):
"""カウントを増加させるメソッド"""
self._count += 1
print(f"Current count: {self._count}")

def reset(self):
"""カウントをリセットするメソッド"""
self._count = 0
print("Counter reset to 0.")

def get_count(self):
"""現在のカウント値を取得するメソッド"""
return self._count


def main():
counter = Counter() # Counterクラスのインスタンスを作成

while True:
action = input("Enter 'i' to increment, 'r' to reset, or 'q' to quit: ").lower()

if action == 'i':
counter.increment() # カウントを増加
elif action == 'r':
counter.reset() # カウントをリセット
elif action == 'q':
print(f"Final count: {counter.get_count()}") # 最終カウントを表示
break # ループを終了
else:
print("Invalid input. Please enter 'i', 'r', or 'q'.")


if __name__ == "__main__":
main()



例:

class MyObject:
def __init__(self, message, value):
# ヒープに格納されるオブジェクトの属性を初期化
self.message = message
self.value = value

def display_message(self):
# ヒープからオブジェクトのメッセージを取得して表示
print(f"Message: {self.message}")

def update_value(self, new_value):
# オブジェクトの値を更新
self.value = new_value
print(f"Value updated to: {self.value}")

def create_object():
# スタックにローカル変数が格納される
local_variable = "I am local" # スタックに格納される
print(local_variable) # スタックから値を取得

# ヒープにオブジェクトを作成
my_object = MyObject("I am an object", 42) # ヒープに格納される
my_object.display_message() # ヒープからオブジェクトのプロパティを取得

# my_objectの参照を返す
return my_object

# メイン処理
if __name__ == "__main__":
obj = create_object() # create_objectが呼ばれ、ローカル変数がスタックに追加される
print(f"Initial value: {obj.value}") # ヒープに格納されたオブジェクトのプロパティを参照
obj.update_value(100) # オブジェクトの値を更新





7. Dart

  • レベル: 高レベル言語
  • メモリ管理: 自動管理。ガベージコレクション(GC)が動的メモリを解放する。
  • 書き方: Googleが開発した、モダンな構文を持つオブジェクト指向プログラミング言語。主にFlutterフレームワークと組み合わせてモバイルアプリやWebアプリ開発に使用される。例:
    void main() {
    int num = 10;
    print(num);
    }
  • できること: クロスプラットフォームのアプリケーション開発、特にモバイルアプリの開発で強みがある。
  • できないこと: ネイティブコードの低レベルな操作は制限される。Flutter以外の用途ではまだ広範に使われていない。

例:


class Counter {
int _count = 0; // 初期値を0に設定

// 現在のカウント値を取得するメソッド
int get count => _count;

// カウントを増加させるメソッド
void increment() {
_count++;
print("Current count is: $_count");
}

// カウントをリセットするメソッド
void reset() {
_count = 0;
print("Counter reset. Current count is: $_count");
}
}

void main() {
Counter counter = Counter(); // Counterクラスのインスタンスを作成

counter.increment(); // カウントを1増加
counter.increment(); // カウントをさらに1増加
print("Final count after increments: ${counter.count}"); // 現在のカウントを出力

counter.reset(); // カウントをリセット
}



例:


class MyObject {
String _message;
int _value;

MyObject(this._message, this._value);

// メッセージの取得
String get message => _message;

// 値の取得と更新
int get value => _value;
set value(int newValue) {
_value = newValue;
print("MyObject value updated to: $_value");
}

// メッセージを表示するメソッド
void displayMessage() {
print("Message: $_message");
}
}

void createObject() {
// 定数として再代入不可のローカル変数
final String localConstant = "I am a constant";
// 再代入可能なローカル変数
String localVariable = "I am a local variable";

// オブジェクトを作成(プロパティは変更可能)
final MyObject myObject = MyObject("I am an object", 42);

print(localConstant); // 定数を出力
print(localVariable); // ローカル変数を出力
myObject.displayMessage(); // オブジェクトのメッセージを出力

// 再代入可能なローカル変数の更新
localVariable = "Updated local variable";
print(localVariable); // 更新後のローカル変数

// プロパティの更新と出力
myObject.value = 100;
print("Current myObject.value: ${myObject.value}");
}

void main() {
createObject();
}





まとめ

言語レベルメモリ管理書き方の特徴できることできないこと
C低-中手動管理ハードウェア寄り、ポインタ使用組み込み、OS、デバイスドライバ高レベルの抽象化、手動管理の手間が大きい
C++中間手動&自動(スマートポインタ)オブジェクト指向、テンプレートゲーム開発、アプリ、ハードウェア制御自動GCなし、メモリリークに注意が必要
Java自動(GC)オブジェクト指向、クラスベースエンタープライズ、Web、Androidシステム操作の低レベル制御が困難
C#自動(GC).NET統合、シンプルデスクトップ、Web、ゲーム(Unity)Windows向けが強い
JavaScript自動(GC)Web向け、スクリプト言語Webアプリ、サーバーサイド(Node.js)低レベル操作が困難
Python自動(GC)インデントベース、シンプルデータサイエンス、AI、Webパフォーマンスが低い、低レベル操作が苦手
Dart自動(GC)モダン、Flutterで使用クロスプラットフォームのアプリ開発低レベル操作が困難、Flutter以外での普及がまだ少ない


CPPとC#の関数に焦点を当てて比較してみる。