こんなお悩みにお答えします。
アドレスとはメインメモリ上の場所を示す番号
こう言われてもわけがわからないですよね。
それもそのはず、アドレスがわからない理由はメインメモリについて知らないからです。
アドレスを理解するにはメインメモリとは何かと、どう使われるのかの理解が必須です。
メインメモリについては以下の記事で初心者向けにわかりやすく解説しています。
さっぱりわからないという方は以下の記事を読んでみてください。
完全に理解できなくても何となくわかればOKです。
こちらもCHECK
-
【初心者向け】コンピュータとプログラムの仕組みを図解でわかりやすく解説
コンピュータってどんな仕組みで動いてるの?CPUとかメモリとかって聞くけど、どんな働きをしてるの?わかりやすく教えてほしい。 プログラムってパソコン上でどうやって動いてるの?初心者でも理解できるように ...
続きを見る
以下の記事はスタック領域の仕組みまで読めばOKです。
こちらもCHECK
-
スタック領域・ヒープ領域・静的領域の仕組みと違いをわかりやすく解説
プログラムを実行するとメインメモリはどうやって使われるの? スタック領域・ヒープ領域・静的領域ってどんな仕組み?それぞれどう違うの? こんな疑問にお答えします。 おゆプログラマーにとってメインメモリの ...
続きを見る
それではアドレスについて解説していきます。
上の記事では変数がメモリに保存される様子を解説しましたが、保存した変数を使いたい時にはどうすればよいのでしょうか。
例えば以下のプログラムの動きを考えてみます。
例:
#include <stdio.h> void main() { int num=10; char chara='A'; printf("num=%d\n",num); }
実行結果
num=10
numとcharaはそれぞれメインメモリのスタック領域に以下のように格納されます。
図の1マスはメインメモリ内のスタック領域のメモリセル1つを表しています。
1行が32マスあるので、4バイト(32ビット)分のデータが保存できます。
整数型の変数numには図の1行分(4バイト分)、charaには8マス分(1バイト分)の領域が割り当てられます。
それ以外の領域には変数とは関係のない値が保存されます。
実際はCPUのレジスタが空いていればローカル変数はそこへ保存されます。しかしここではイメージを掴んでもらうことが目的なのでCPUのレジスタは埋まっているとして解説しています。
例ではprintfでnumの値を表示するよう書かれています。
これを実行するため、CPUはまずnumの値を保存先のメインメモリに問い合わせます。
ですがメインメモリはどこにどの変数が保存されているか知らないので、以下のように問い合わせるとメインメモリは困ってしまいます。
これを解決するのがアドレスです。
先ほどのメインメモリ領域を1バイトごとに分け、左上から順に番号を振っていきます。
この番号がアドレスです。
スタック領域のアドレスは大きい数字から順に振られていくので、例として100から順に番号を振ります。
実際のアドレス値はメインメモリのどの位置にスタック領域が作られるかによって変わります。ですがここでは想像しやすいよう、アドレスを100始まりで振っていきます。
このようにしてメインメモリ内にアドレスを振り、CPUのセリフを以下のように変えます。
アドレスとバイト数を指定すればちゃんと目的の値が得られるんです。
このようにコンピュータ内部ではアドレスを使って変数を管理しています。
ちなみに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のアドレスを代入(初期化) 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++のエラーが解決できない。ググってもわからない。わかる人に解説してほしい。 こんなお悩みにお答えしま ...
続きを見る