Contents
ポインターの基本概念と宣言方法
C言語におけるポインターは、変数のメモリアドレスを直接操作する仕組みです。初心者が理解しやすいように、以下のポイントで解説します。
変数とアドレスの関係
変数に値が格納されるのはメモリ上であり、その場所をアドレス(ポインター)で参照できます。例えばint a = 10;では、aは10という値を持つだけでなく、メモリ上の特定の位置(例:0x7fff5fbff84c)も指しています。
ポインター変数の宣言文法
ポインター変数はint *p;のように宣言します。この*は「pがint型のアドレスを指す」という意味です。
ポインター演算子の使い方
&a:変数aのアドレスを取得*p:ポインターpが指す値にアクセス
アドレス操作と値変更の仕組み
ポインターは「メモリ上のデータを間接的に操作する」という特徴を持ちます。この点をステップバイステップで理解しましょう。
間接参照演算子の動作原理
*p = 30;とすることで、pが指す変数の値が直接変更されます。これは「ポインターを通してデータにアクセスする」仕組みです。
ポインターによる値の書き換え
以下のように、int a = 10; int *p = &a; *p = 30;とすることでaの値が30になります。この操作は配列処理や関数間でデータを効率的に変更するのに役立ちます。
ポインターの加減算
ポインターに整数を加算/減算すると、アドレスが要素サイズ分ずれます。例えばint *p = &a; p++;はpを4バイト(int型)分進めます。
配列とポインターの関係性
配列とポインターは密接な関係を持ち、C言語では「配列名がポインターになる」という仕組みがあります。ただし、配列名はポインターにデカイするが、ポインター変数とは異なる点に注意が必要です(後述)。
配列名がポインターになる仕組み
int arr[5]; int *p = arr;のように、配列名arrは&arr[0]と同じアドレスを指します。これは「配列の先頭要素へのポインター」と解釈されます。
配列要素へのポインターアクセス
arr[i]と*(arr + i)は同じ意味です。このようにして、ポインターで配列操作を実現できます。
ポインターを使用した配列処理
以下のようなコードでは、ポインターを使って配列の要素を順にアクセスできます。
|
1 2 3 4 5 6 |
int arr[] = {1, 2, 3}; int *p = arr; for (int i = 0; i < 3; i++) { printf("%d\n", *p++); } |
配列とポインターの違い
| 項目 | 配列 | ポインター変数 |
|---|---|---|
| メモリ確保 | コンパイル時に固定 | 実行時に動的に確保可能 |
| サイズ変更 | 不可(長さは定義時確定) | 可(mallocで動的調整可能) |
| アドレス操作 | 配列名は&arr[0]になる |
ポインター変数はアドレスを直接保持 |
動的メモリ確保(malloc/free)の使い方
C言語ではmalloc関数で動的にメモリを確保し、freeで解放します。これは配列サイズが変動するなど、柔軟なデータ処理が必要な場面で有効です。
メモリ確保関数の基本呼び出し
|
1 2 |
int *arr = (int *)malloc(5 * sizeof(int)); |
確保されたメモリの解放処理
free(arr);により、動的に確保したメモリを開放します。
注意:
mallocで確保したメモリは必ずfreeして解放する必要があります。それがないとメモリリークが発生します。
メモリリークを防ぐポイント
- 常に
mallocで確保したメモリはfreeする NULLチェックを忘れずに実施
ポインターを用いた実用的なコード例
ポインターは、構造体操作や関数間でのデータ共有など、実践的なプログラミングに不可欠です。
構造体へのポインター操作
|
1 2 3 4 5 6 7 8 |
struct Student { char name[50]; int age; }; struct Student *s = malloc(sizeof(struct Student)); strcpy(s->name, "田中"); s->age = 20; |
関数間でのポインター渡し
関数にポインターを渡すことで、複数の変数を直接操作できます。例:void swap(int *a, int *b)。
複雑なデータ構造の実装
リンクリストや木構造などは、ポインターで要素間の接続を実現します。
理解度チェック:演習問題と解答
各セクションの要点を確認するための演習問題です。解答はコード形式で厳密な構文を示し、間違いやすいポイントを強調します。
基礎問題
- 変数
x = 5;にアクセスするポインターpを宣言し、値を表示するプログラムを作成してください。
|
1 2 3 4 5 6 7 |
#include <stdio.h> int main() { int x = 5; int *p = &x; // pはxのアドレスを指すポインター変数 printf("%d\n", *p); // **間接参照演算子: ポインターが指す値にアクセス** } |
応用問題
- 配列
arr[3] = {1, 2, 3}をポインターで操作し、合計値を求めるプログラムを作成してください。
|
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdio.h> int main() { int arr[] = {1, 2, 3}; int *p = arr; // 配列名arrは配列の先頭アドレスにデカイする int sum = 0; for (int i = 0; i < 3; i++) { sum += *(p + i); // **ポインター加算による配列アクセス: p+iがi番目の要素を指す** } printf("%d\n", sum); } |
課題プログラミング
mallocを使用して動的配列を作成し、ユーザー入力で要素数を指定するプログラムを作成してください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <stdio.h> #include <stdlib.h> int main() { int n; printf("要素数: "); scanf("%d", &n); int *arr = (int *)malloc(n * sizeof(int)); if (arr == NULL) { // **メモリ確保失敗時のチェック** printf("メモリ確保に失敗しました。\n"); return 1; } for (int i = 0; i < n; i++) { printf("%d番目の値: ", i + 1); scanf("%d", &arr[i]); // **配列アクセス: arr[i]はポインター演算子*(arr+i)と同じ** } free(arr); // **メモリ解放: 動的確保したメモリを開放** } |
まとめ
本記事では、C言語のポインターに関する以下をステップバイステップで解説しました。
- 変数とアドレスの関係:
&演算子を使ってアドレスを取得する方法 - ポインター操作:間接参照(
*p)や加減算によるメモリアクセス - 配列とポインター:配列名がポインターになる仕組みと実践的な使い方
- 動的メモリ管理:
malloc/freeの正しい使い方とメモリリーク防止 - 応用コード例:構造体や関数間でのポインター利用
演習問題を通じて理解度を深め、実際のプログラミングで活かせる知識にしましょう。