記事には広告を含む場合があります。

C言語入門講座

【C言語】アドレスとポインタをわかりやすく解説!使うメリットは?

2024年11月9日

おゆ

組み込み系プログラマとして5年働いていた元エンジニアです。得意言語はC言語とC++。本サイトでは学生および新人組み込み系プログラマに向けてプログラミング知識をわかりやすく解説しています。

ポインタって何?使うメリットは?わかりやすく教えてほしい。
アドレスって何?ポインタに関係あるの?メモリのアドレスって言われてもピンとこない…

こんなお悩みにお答えします。

アドレスとはメインメモリ上の場所を示す番号

おゆ
プログラミングでいうアドレスとはメインメモリ上に振られた番号のことです。
???

こう言われてもわけがわからないですよね。

それもそのはず、アドレスがわからない理由はメインメモリについて知らないからです。

アドレスを理解するにはメインメモリとは何かと、どう使われるのかの理解が必須です。

メインメモリについては以下の記事で初心者向けにわかりやすく解説しています。

さっぱりわからないという方は以下の記事を読んでみてください。

完全に理解できなくても何となくわかればOKです。

こちらもCHECK

【初心者向け】コンピュータとプログラムの仕組みを図解でわかりやすく解説

コンピュータってどんな仕組みで動いてるの?CPUとかメモリとかって聞くけど、どんな働きをしてるの?わかりやすく教えてほしい。 プログラムってパソコン上でどうやって動いてるの?初心者でも理解できるように ...

続きを見る

おゆ
Googleで「コンピュータ 仕組み わかりやすく」と調べると検索トップに出てくる記事です。わかりやすさには定評がある記事なので読みやすいと思います。

以下の記事はスタック領域の仕組みまで読めばOKです。

こちらもCHECK

スタック領域・ヒープ領域・静的領域の仕組みと違いをわかりやすく解説

プログラムを実行するとメインメモリはどうやって使われるの? スタック領域・ヒープ領域・静的領域ってどんな仕組み?それぞれどう違うの? こんな疑問にお答えします。 おゆプログラマーにとってメインメモリの ...

続きを見る

ふう…読み終わった!プログラムを動かすとパソコンの中に入ってるCPUとメインメモリが主に動くんだね。メインメモリには変数とかを保存するんだな。変数の性質によってメインメモリ内のどこに保存するのかを変えてるのか。
おゆ
そうそう!メインメモリの使われ方が大まかにわかれば完璧です!

それではアドレスについて解説していきます。

上の記事では変数がメモリに保存される様子を解説しましたが、保存した変数を使いたい時にはどうすればよいのでしょうか。

例えば以下のプログラムの動きを考えてみます。

例:

#include <stdio.h>
void main()
{
    int num=10;
    char chara='A';
    printf("num=%d\n",num);
}

実行結果

num=10

numとcharaはそれぞれメインメモリのスタック領域に以下のように格納されます。
スタック領域

おゆ
スタック領域とはメインメモリ内に確保される領域の1つでしたね。ローカル変数はスタック領域に格納されます。

図の1マスはメインメモリ内のスタック領域のメモリセル1つを表しています。

1行が32マスあるので、4バイト(32ビット)分のデータが保存できます。

整数型の変数numには図の1行分(4バイト分)、charaには8マス分(1バイト分)の領域が割り当てられます。

おゆ
メインメモリには2進数に変換された値が保存されます。10進数の10は2進数で1010、文字Aは2進数の1000001に置き換えられて保存されます。上位桁には0が入ります。

それ以外の領域には変数とは関係のない値が保存されます。

実際はCPUのレジスタが空いていればローカル変数はそこへ保存されます。しかしここではイメージを掴んでもらうことが目的なのでCPUのレジスタは埋まっているとして解説しています。

例ではprintfでnumの値を表示するよう書かれています。

これを実行するため、CPUはまずnumの値を保存先のメインメモリに問い合わせます。

ですがメインメモリはどこにどの変数が保存されているか知らないので、以下のように問い合わせるとメインメモリは困ってしまいます。
CPUとメインメモリのやり取り1

これを解決するのがアドレスです。

先ほどのメインメモリ領域を1バイトごとに分け、左上から順に番号を振っていきます。

この番号がアドレスです。

スタック領域のアドレスは大きい数字から順に振られていくので、例として100から順に番号を振ります。
アドレスの振り方

おゆ
メインメモリのデータはバイト単位で処理されるので、1ビットごとにアドレスを振る必要はありません。

実際のアドレス値はメインメモリのどの位置にスタック領域が作られるかによって変わります。ですがここでは想像しやすいよう、アドレスを100始まりで振っていきます。

このようにしてメインメモリ内にアドレスを振り、CPUのセリフを以下のように変えます。
CPUとメインメモリのやり取り2

アドレスとバイト数を指定すればちゃんと目的の値が得られるんです。

このようにコンピュータ内部ではアドレスを使って変数を管理しています

ちなみにcharaの値が欲しければ「アドレス5から1バイト分の値を教えて!」と言います。

得られた値とASCIIコード表(2進数と文字の対応表)と照らし合わせれば変数charaにはAが入っているとわかります。

つまりアドレスとはメインメモリの場所を特定するために振られた番号のことです

変数に&を付けるとアドレスの中身が見れる

実は変数の頭にアンパサンド(&)を付けると変数が保存されている場所の先頭アドレスが得られます。

例:

#include <stdio.h>
void main()
{
    int num=10;
    char chara='A';
    printf("num address=%d\n",&num);
    printf("chara address=%d\n",&chara);
}

実行結果

num address=96468236
chara address=96468235

出力されるのは先頭アドレスなので整数型変数numはアドレス96468236から96468239までの4バイト分に保存されています。

文字型変数は1バイト分なので、charaは96468235に保存されています。

ポインタとは変数のアドレスを保存する変数

コンピュータ内部ではアドレスを使って変数を管理しています。

ということはプログラマもアドレスを指定して変数を操れるはずです。

このときに使うのがポインタです。

ポインタは変数のアドレスを保存するための変数です。

おゆ
これだけ聞くと混乱してしまうかもしれませんが、例を見ると何となく理解してもらえるかと思います。

ポインタの宣言方法

データ型 *変数名;

変数名の前にアスタリスク(*)を付ける。

ポインタと同じデータ型の変数のアドレスを格納できる。

ポインタの使い方

初期化方法:
変数名=&変数名;

値の取り出し方:
*変数名

アドレスの取り出し方:
変数名

例:

#include <stdio.h>
void main()
{
    int num=10;
    int *p; //ポインタの宣言
    p=&num; //ポインタにnumのアドレスを代入(初期化)
    printf("num=%d\n",num);
    printf("num=%d\n",*p); //アドレスに格納されている値は*を付けて取り出す
    printf("num address=%d\n",&num);
    printf("num address=%d\n",p); //アドレスを取り出す
}

実行結果

num=10
num=10
num address=71301444
num address=71301444

ポインタ宣言の書き方は変数宣言と似ています。

変数名の前にアスタリスク(*)を入れるとポインタの宣言になります。

例ではポインタpに変数numのアドレスを代入しています。

*pと書くとポインタpのアドレスに格納されている値、つまりnumの値を指します。

メインメモリ内の様子を図で表すとこのようになります。
ポインタとスタック領域

「int *p=&num」と書いてポインタ宣言と同時にアドレスを代入することもできます。

ポインタを使うメリット

ポインタって必要?&を付けて変数のアドレスを表せるのならそれでよくない?

と思う方もいらっしゃるかと思います。

おゆ
確かに上の例ではポインタがなくても困りません。しかしポインタがなくては困る場面はいくつかあります。

例えば関数内で実引数(関数呼び出し時に引数として渡した変数)の値を変更したいときにはポインタを使う必要があります。

詳しくはこちら

【C/C++】関数の値渡し・ポインタ渡し(アドレス渡し)・参照渡し

C言語、C++の関数には値渡しとポインタ渡し(アドレス渡し)と参照渡しの3種類があります。 ここではその違いを解説します。 関数への値渡し 関数へ変数を渡すとき、特にアドレスやポインタを使わなければ値 ...

続きを見る

また配列や構造体を引数として関数に渡すときにもポインタがあると便利です。

詳しくはこちら

【C言語】配列を関数の引数として渡す!サイズは渡す?ポインタは使う?

配列を引数として渡す方法を解説します。 方法は複数あるのですが、ここでは「これを使っておけばOK」という方法を紹介します。 配列を引数として関数に渡す方法 配列で受け取る方法【通常はこれ】 配列で受け ...

続きを見る

malloc関数を用いたメモリ領域の動的確保にも使われます。

C言語で行き詰まったら…

C言語・C++がわからない時に質問できるサイト・サービス5選

C言語を独学で勉強しているけど内容がイマイチわからない。もはや何がわからないのかもわからない。 C++のエラーが解決できない。ググってもわからない。わかる人に解説してほしい。 こんなお悩みにお答えしま ...

続きを見る

ブログランキング参加中。クリックしてもらえると励みになります。

ブログランキング・にほんブログ村へ

-C言語入門講座