ポインタ配列とは、その名の通り、各要素がポインタである配列のことです。特に char*
型のポインタ配列は、複数の文字列をまとめて管理する際に非常に便利です。
通常の二次元配列 char str[4][20];
では、すべての要素が固定の長さ(この場合は20バイト)を確保してしまいますが、ポインタ配列を使えば、文字列の長さに応じて効率的にメモリを使用できます。
これは、配列の各要素が、メモリ上の別々の場所に格納されている文字列の**先頭アドレスを指している(ポイントしている)**イメージです。
ポインタ配列の使い方
char*
の配列を定義し、各要素に文字列リテラルのアドレスを格納します。
#include <stdio.h>
int main(void) {
// char* (文字列へのポインタ) を格納する配列を定義・初期化
char* lang_list[4] = {
"C",
"Python",
"JavaScript",
"Rust"
};
printf("--- プログラミング言語リスト ---\n");
printf("要素番号 | ポインタが指す文字列\n");
printf("------------------------------------\n");
for (int i = 0; i < 4; i++) {
// lang_list[i] は、各文字列へのポインタ
printf(" data[%d] | %s\n", i, lang_list[i]);
}
// ポインタの値(アドレス)そのものを表示したい場合
printf("\n--- ポインタ(アドレス)情報 ---\n");
printf("要素番号 | 格納されているアドレス\n");
printf("------------------------------------\n");
for (int i = 0; i < 4; i++) {
// %p はポインタ(アドレス)を表示するための書式指定子
printf(" data[%d] | %p\n", i, lang_list[i]);
}
return 0;
}
実行結果:
--- プログラミング言語リスト ---
要素番号 | ポインタが指す文字列
------------------------------------
data[0] | C
data[1] | Python
data[2] | JavaScript
data[3] | Rust
--- ポインタ(アドレス)情報 ---
要素番号 | 格納されているアドレス
------------------------------------
data[0] | 00403010
data[1] | 00403012
data[2] | 00403019
data[3] | 00403026
このように、lang_list
という一つの配列変数を使って、長さの異なる複数の文字列を簡単に扱うことができます。
関数ポインタ:関数を「変数」のように扱う
C言語では、変数だけでなく関数もメモリ上にアドレスを持っています。そして、その関数のアドレスを格納できる特殊なポインタが**「関数ポインタ」**です。
関数ポインタを使うと、関数をまるで変数のように扱えます。例えば、**状況に応じて呼び出す関数を切り替えたり、ある関数の引数として別の関数を渡したりする(コールバック)**といった高度なプログラミングが可能になります。
関数ポインタの使い方
関数ポインタの宣言は少し独特です。 戻り値の型 (*ポインタ名)(引数の型リスト);
サンプルコード: 2つの整数に対して、足し算を行う関数と引き算を行う関数を用意し、関数ポインタで切り替えて呼び出してみましょう。
#include <stdio.h>
// 関数のプロトタイプ宣言
int add(int a, int b);
int subtract(int a, int b);
int main(void) {
int result;
// 「int型の引数を2つ取り、int型の値を返す関数」を指すポインタを宣言
int (*calculator_ptr)(int, int);
// 1. 関数ポインタに add 関数のアドレスを代入
calculator_ptr = add;
// 関数ポインタ経由で add 関数を呼び出す
result = calculator_ptr(10, 3);
printf("add関数を呼び出した結果: %d\n", result);
// 2. 関数ポインタに subtract 関数のアドレスを代入
calculator_ptr = subtract;
// 関数ポインタ経由で subtract 関数を呼び出す
result = calculator_ptr(10, 3);
printf("subtract関数を呼び出した結果: %d\n", result);
// (*ポインタ名) という古い形式の呼び出し方も可能
result = (*calculator_ptr)(10, 3);
printf("古い形式での呼び出し結果: %d\n", result);
return 0;
}
// 足し算を行う関数
int add(int a, int b) {
return a + b;
}
// 引き算を行う関数
int subtract(int a, int b) {
return a - b;
}
実行結果:
add関数を呼び出した結果: 13
subtract関数を呼び出した結果: 7
古い形式での呼び出し結果: 7
calculator_ptr
という一つのポインタ変数が、状況に応じてadd
関数を指したり、subtract
関数を指したりと、その役割を変えているのが分かります。これにより、プログラムのロジックを動的に変更することが可能になります。