🕌

C言語のメモリとポインタってなに?

に公開

🚀 C言語と仲良くしよう

はじめに

C言語を学習し始めた文系の方やプログラミング初学者にとって、「ポインタ」と「メモリの直接操作」はピンと来ない

本記事では、「メモリに直接書き込めることが何がすごいのか?」という疑問を解消し、コードを通じて、C言語を理解しようとするC言語初心者の記録です。


💡 ポインタが「すごい」理由 — 速度と効率

とある人との会話で、「C言語を使う最大のメリットはポインタにあり、コンピューター(マイコン)のメモリに直接1, 0を書き込めることだ」というのを教えてもらった。

Pythonをかじった程度の私にとって、それが何故すごいのか全く分からないので、まずAIに聞いてみた。

私:「メモリに直接書き込めるのが何がすごいねん?

AI:以下回答

1. 圧倒的な実行速度とメモリ効率 🚀

ポインタを使うC言語は、メモリを無駄にせず、ギリギリまで効率的なプログラムが作れる。

  • 無駄な処理がない: Pythonなどの高級言語と違い、C言語ではメモリ管理をプログラマが直接行うため、メモリが限られた車のECU(電子制御ユニット)などのマイコン環境では、この効率の良さが実行速度と安定性に決定的な差を生むらしい。

👉 結論: ポインタがすごいのは、抽象化された「箱(変数)」のフタを開け、中身を正確に配置・制御できる、つまりコンピュータを意のままに操る鍵だからだ。


💻 実践:ポインタを使ってメモリに「書き込む」処理を実装する

言葉だけでは理解が進まないので、実際にポインタの基本的な役割である**「間接参照(値の変更)」**を実装し、メモリへの書き込みを体験する。

処理コード

#include <stdio.h>

int main(void) {
    // ① 通常のint型変数 (値: 10)
    int value = 10; 
    
    // ② ポインタ変数 (&value は valueのアドレスを取得)
    int *ptr_value = &value; 
    
    printf("--- 実行前 ---\n");
    printf("valueのアドレス: %p\n", &value);
    printf("ptr_valueが指すアドレス: %p\n", ptr_value);
    printf("valueの値: %d\n", value);
    
    // ③ 間接演算子(*)を使って、ポインタの指す先(value)に999を書き込む
    // この一行が、メモリに直接書き込んでいる処理
    *ptr_value = 999; 
    
    printf("\n--- 書き込み後 ---\n");
    printf("valueの値: %d\n", value); // 値が999に変わっている!
    
    return 0;
}

この *ptr_value = 999; という一行こそが、**「ポインタを使ってメモリに直接書き込んでいる処理」**変数の名前 value を使わず、**メモリアドレス(住所)**だけを頼りにデータを書き換えられていることが確認できる。


🗺️ Cプログラムの三つの「部屋」とメモリ構造

さらによくわからないC言語のメモリについて理解するため、変数が実際どこに配置されるかを探る。以下のコードは、C言語が利用するデータ領域、スタック領域、ヒープ領域のアドレスを比較するものだ。

サンプルコード(データ領域)

#include <stdio.h>
#include <stdlib.h>

// グローバル変数:データ領域に配置
int g_global1 = 9999;
int g_global2 = 9999; 

int main(void) {
    // ローカル変数:スタック領域に配置
    int local1 = 1000;
    int local2 = 1000;
    
    // mallocで確保したメモリ:ヒープ領域に配置
    int *ptr_malloc1 = (int*)malloc(sizeof(int));
    int *ptr_malloc2 = (int*)malloc(sizeof(int));
    
    // ...
    // 各領域のアドレス表示処理
    // ...
    
    // 忘れずに解放!
    free(ptr_malloc1); free(ptr_malloc2);
    return 0; 
}

領域ごとの特徴

メモリ領域 変数例 特徴とポインタとの関係
データ領域 g_global1 プログラム終了まで存在。アドレスは固定。
スタック領域 local1 関数が終了すると自動解放。アドレスは通常、連続して減少する傾向。
ヒープ領域 malloc()の戻り値 mallocfreeで手動管理が必要。アドレスは増加傾向。ポインタが最も活躍する領域。

グローバル変数=他のフォルダのコードでも使いまわせる。(便利だがメモリ使いぱなし)
ローカル変数は=その関数の内のみでしか使用できない。(関数が終わると解放)
malloc関数=メモリの管理人
メモリ使用前に連絡することでデータの住所(アドレス)だけをくれるのでポインタで指定してそのアドレスを使用する、使い終わったら手動で管理人に返却しないといけない(手動で必要な分のメモリだけ管理人に確保して貰えるので非常にメモリを削減できるらしい)

ポインタは、メモリにおいて、どの領域のどの番地を操作するかを正確に指示する「住所」の役割を果たしている。特にヒープ領域は、ポインタがないとアクセスすらできないらしい。

結論

メモリが限定的な環境ではC言語が非常に魅力的。
C言語のポインタはメモリを効率的かつ最小限にする。他の高級言語ではそれができないらしい。
メモリに関してはコードを実行しても視覚的や感覚的に実感しにくい上に、初心者プログラマはメモリの使用削減しようとまず頓着がないので関心が薄いように思う。
メモリに直接書き込めるというのはパソコンがクラッシュする危険性も孕んでいるので必要性がないなら実行するのも躊躇われる…
C言語と仲良くなるのは難しい

Discussion