C言語のアドレス演算子(&)と間接演算子(*)を完全解説!ポインタの基本を初心者向けにやさしく理解
生徒
「C言語を勉強していたら、&とか*という記号が出てきました。これは何ですか?」
先生
「それはC言語のポインタを扱うときに使う、とても重要な演算子です。&はアドレス演算子、*は間接演算子と呼ばれます。」
生徒
「アドレスって住所のことですよね?プログラムにも住所があるんですか?」
先生
「その通りです。コンピュータのメモリには、すべてのデータに住所のような番号がついています。C言語では、その住所を使ってデータを操作することができます。」
生徒
「なるほど。じゃあその住所を取得したり、そこにあるデータを取り出したりするための記号なんですね!」
先生
「その理解で正しいです。それでは、C言語のアドレス演算子と間接演算子の仕組みを、初心者向けに順番に見ていきましょう。」
1. C言語のアドレス演算子(&)とは?
C言語のアドレス演算子とは、変数が保存されているメモリ上の場所(アドレス)を取得するための記号です。記号は&を使います。
コンピュータのメモリは、大きなロッカーのようなものです。それぞれのロッカーには番号が付いており、その番号がメモリアドレスです。変数を作ると、そのロッカーのどこかにデータが保存されます。
アドレス演算子を使うと、そのロッカー番号を取得できます。
#include <stdio.h>
int main()
{
int number = 10;
printf("変数numberの値: %d\n", number);
printf("変数numberのアドレス: %p\n", &number);
return 0;
}
このプログラムでは、&numberによって変数numberのメモリアドレスを取得しています。
変数numberの値: 10
変数numberのアドレス: 0x7ffeefbff5ac
表示される値は環境によって変わりますが、これはメモリ上の住所を表しています。
2. 間接演算子(*)とは?
間接演算子*は、アドレスが示している場所のデータを取り出すための演算子です。
少しイメージしやすい例えをしてみましょう。
メモリのアドレスは「家の住所」です。そして、その住所にある家の中に「データ」があります。
つまり次のような関係になります。
- アドレス → 家の住所
- データ → 家の中にある物
間接演算子*は、住所をたどって中身を取り出す操作です。
3. ポインタ変数と間接演算子の基本
アドレスを保存するための変数をポインタ変数と呼びます。
ポインタとは「場所を指し示すもの」という意味です。つまり、メモリの場所を覚えておく変数です。
#include <stdio.h>
int main()
{
int a = 5;
int *p;
p = &a;
printf("aの値: %d\n", a);
printf("aのアドレス: %p\n", &a);
printf("ポインタpが指す値: %d\n", *p);
return 0;
}
aの値: 5
aのアドレス: 0x7ffd12345678
ポインタpが指す値: 5
このプログラムでは次のことをしています。
&a→ 変数aのアドレスを取得p→ アドレスを保存*p→ そのアドレスにあるデータを取得
4. 間接演算子を使って値を変更する
間接演算子は、値を取り出すだけではありません。アドレス先の値を書き換えることもできます。
つまり、ポインタを使うと別の場所から変数の値を変更できます。
#include <stdio.h>
int main()
{
int value = 20;
int *ptr;
ptr = &value;
*ptr = 50;
printf("valueの値: %d\n", value);
return 0;
}
valueの値: 50
ここでは、*ptr = 50と書くことで、ポインタが指している変数valueの値を変更しています。
つまりポインタを通して元の変数を書き換えているのです。
5. アドレス演算子と間接演算子の関係
アドレス演算子と間接演算子は、セットで理解するととてもわかりやすくなります。
関係は次のようになります。
&→ アドレスを取得する*→ アドレスから値を取り出す
次のプログラムを見ると、流れが理解しやすくなります。
#include <stdio.h>
int main()
{
int number = 100;
int *pointer;
pointer = &number;
printf("number: %d\n", number);
printf("pointerが指す値: %d\n", *pointer);
return 0;
}
このように、
変数 → アドレス取得 → ポインタ保存 → 間接演算子で値取得
という流れになります。
6. 初心者がよく間違えるポイント
C言語のポインタでは、初心者が混乱しやすいポイントがいくつかあります。
特に次の点は覚えておくと理解しやすくなります。
&はアドレスを取得する*はアドレス先の値を取得する*はポインタ宣言にも使われる
例えば次のコードです。
int *p;
この場合の*は間接演算子ではなくポインタ宣言です。つまり「pはポインタ変数」という意味になります。
一方で、次のコードでは意味が変わります。
*p
こちらは「ポインタpが指している場所の値」を意味します。
この違いを理解すると、C言語のポインタの理解が一気に深まります。
7. C言語のポインタ理解で重要な考え方
C言語のポインタは最初は難しく感じるかもしれません。しかし、基本はとてもシンプルです。
覚えるべき考え方は次の三つです。
- 変数にはメモリアドレスがある
&でアドレスを取得できる*でアドレス先の値を扱える
この仕組みを理解すると、C言語の多くの機能が見えてきます。配列、関数、メモリ操作などもポインタと深く関係しています。
そのため、C言語を学習するうえでアドレス演算子と間接演算子は最も重要な基礎知識の一つと言えるでしょう。
まとめ
アドレス演算子と間接演算子の基本を振り返る
ここまで、C言語のポインタの基礎として非常に重要な「アドレス演算子」と「間接演算子」について学んできました。C言語を学習していると、&や*という記号が頻繁に登場します。これらは単なる記号ではなく、メモリとデータの関係を理解するための重要な仕組みです。
C言語では、すべての変数がコンピュータのメモリ上に保存されます。そして、そのメモリの場所にはそれぞれ固有の番号が割り当てられています。この番号のことを「メモリアドレス」と呼びます。アドレス演算子&を使うと、その変数が保存されているメモリアドレスを取得することができます。
一方で、間接演算子*は、そのアドレスが指している場所にあるデータを取り出すために使われます。つまり、アドレスを使って実際の値を取得したり変更したりする操作が可能になります。C言語のポインタは、この「アドレス」と「値」をつなぐ役割を持っています。
ポインタとアドレスの関係を整理する
C言語のポインタを理解するためには、次の三つの関係をしっかり整理することが大切です。
- 変数には必ずメモリアドレスが存在する
- アドレス演算子
&でそのアドレスを取得できる - 間接演算子
*でアドレス先の値を扱うことができる
この三つのポイントを理解することで、C言語のポインタの基本構造が見えてきます。プログラムの中では「値」と「アドレス」の二つの視点でデータを扱うことができるのです。
C言語のポインタ理解に役立つサンプルプログラム
ここで、アドレス演算子と間接演算子の関係をもう一度確認できるサンプルプログラムを見てみましょう。このコードでは、変数のアドレスを取得し、そのアドレスをポインタ変数に保存して、間接演算子を使って値を取り出しています。
#include <stdio.h>
int main()
{
int score = 80;
int *pointer;
pointer = &score;
printf("scoreの値: %d\n", score);
printf("scoreのアドレス: %p\n", &score);
printf("ポインタpointerが指す値: %d\n", *pointer);
return 0;
}
このプログラムでは、まず変数scoreを宣言し、その値として80を代入しています。その後、ポインタ変数pointerを宣言し、アドレス演算子&を使ってscoreのメモリアドレスを取得し、pointerに保存しています。
そして、間接演算子*を使うことで、そのアドレスが指している値を取得しています。つまり、*pointerはscoreの値を意味することになります。
scoreの値: 80
scoreのアドレス: 0x7ffd12345678
ポインタpointerが指す値: 80
このように、C言語ではアドレスを扱うことで、変数をより柔軟に操作することができます。ポインタはC言語の特徴的な機能であり、メモリ操作や効率的なプログラム作成に欠かせない存在です。
ポインタを使って値を書き換える例
C言語の間接演算子は、値を取得するだけではなく、値を書き換えることもできます。ポインタを通して変数の値を変更できる点は、C言語の大きな特徴の一つです。
#include <stdio.h>
int main()
{
int number = 10;
int *ptr;
ptr = &number;
*ptr = 200;
printf("numberの値: %d\n", number);
return 0;
}
numberの値: 200
このプログラムでは、ポインタptrがnumberのアドレスを指しています。そして、*ptr = 200と書くことで、ポインタが指しているメモリの値を変更しています。結果として、numberの値も200に変わります。
このような仕組みは、関数の引数として変数を渡すときや、大きなデータ構造を効率よく扱うときに非常に重要になります。C言語の配列処理、文字列処理、構造体操作、さらには動的メモリ管理など、さまざまな場面でポインタは活躍します。
C言語のポインタを理解するためのコツ
C言語のポインタは初心者がつまずきやすい部分ですが、次の考え方を意識すると理解しやすくなります。
- 変数には必ずメモリアドレスがある
- アドレス演算子でその場所を取得できる
- ポインタはアドレスを保存する変数である
- 間接演算子でその場所のデータを操作できる
この基本を理解すると、C言語のプログラムの見方が大きく変わります。ポインタは難しい概念に見えるかもしれませんが、実際には「アドレスを扱う変数」と「その中身を取り出す操作」というシンプルな構造で成り立っています。
C言語のポインタ、アドレス演算子、間接演算子の理解は、配列、関数、構造体、メモリ管理など多くの分野につながります。プログラミング初心者にとって最初は少し難しく感じるかもしれませんが、サンプルプログラムを繰り返し実行しながら学習することで、確実に理解が深まっていきます。
生徒
先生、今回の学習でポインタのイメージが少しつかめました。C言語では変数に値だけではなく、メモリのアドレスもあるんですよね。
先生
その通りです。C言語のプログラミングでは、変数の値だけではなく、どのメモリに保存されているのかという視点もとても重要になります。アドレス演算子と間接演算子は、その仕組みを理解するための基本になります。
生徒
アドレス演算子は&で、変数のメモリアドレスを取得するんですよね。そしてポインタ変数にそのアドレスを保存するんですよね。
先生
よく覚えていますね。そして、そのポインタが指している場所の値を取り出すときに使うのが間接演算子*です。これを使うことで、ポインタを通して値を読み取ったり変更したりできます。
生徒
つまり、&は住所を取得する操作で、*はその住所にあるデータを取り出す操作なんですね。例えで説明されると理解しやすいです。
先生
その理解はとても大切です。C言語のポインタは、配列処理や関数呼び出し、メモリ管理など多くの機能と関係しています。今後C言語を学習していくと、さらにポインタを使う場面が増えてきます。
生徒
最初は難しく感じましたが、アドレスと値の関係を意識すると理解しやすくなりました。これからポインタの練習プログラムも書いてみたいと思います。
先生
とても良い姿勢ですね。C言語のポインタは実際にコードを書きながら学ぶことで理解が深まります。今回学んだアドレス演算子と間接演算子を何度も使いながら、少しずつ慣れていきましょう。