ポインタのポインタとは
ポインタは変数のアドレスを格納する変数ですので、ポインタ変数自身もメモリ上のどこかにアドレスが割り当てられています。そのポインタ変数のアドレスを格納するためのポインタも作ることができます。これがポインタのポインタと呼ばれるものです。
ポインタのポインタも変数なので、ポインタのポインタのポインタや、ポインタのポインタのポインタのポインタなど、いくつでも繋げることができますが、ソースコードが解りにくくなるため通常使用されるのはポインタのポインタまでです。
ポインタのように、ある変数に割り当てられたアドレスからその変数のデータを間接的に参照することを間接参照(かんせつさんしょう)といいます。また、ポインタのポインタのように多重に間接参照を行うことを多重間接参照といいます。
ポインタのポインタを宣言するには*を2つつけます。
ポインタのポインタの使用例
ポインタのポインタの使用例として月の番号から名称と略称を表示するプログラムをつくってみます。
/*
month.c
月の番号から月の名称と略称を表示するプログラム
*/
/* インクルードヘッダ */
#include <stdio.h>
#include <stdlib.h>
/* プロトタイプ宣言 */
void getMonthName(int month, char **name, char **abbreviation);
/*
メイン
*/
int main(int argc, char *argv[])
{
int n;
char *nameString = NULL;
char *abbreviationString = NULL;
/* 引数のチェック */
if (argc != 2) {
printf("Usage: %s <month number>¥n", argv[0]);
return 0;
}
/* 引数を取得,atoi()でintに変換 */
n = atoi(argv[1]);
/* 番号から月の名称を取得 */
getMonthName(n, &nameString, &abbreviationString);
/* 取得した月名称と略称を出力 */
printf("%s¥n%s¥n", nameString, abbreviationString);
return 0;
}
/*
月名称取得
getMonthName
<概要>
指定された月の名称と略称を出力する
<戻り値>
void
<引数>
int month:(i) 月.1なら1月,2なら2月...
char **name:(o) 月名称文字列へのポインタ
char **abbreviation:(o) 月略称文字列へのポインタ
<補足>
指定された月が1未満なら1月とみなし12を超えるなら12月とみなす。
*/
void getMonthName(int month, char **name, char **abbreviation)
{
/* 月名称 */
static char *monthName[] = {
"January", "February" ,"March" ,"April" ,"May" ,"June",
"July", "August", "September", "October", "November", "December"
};
/* 月略称 */
static char *monthAbbreviation[] = {
"Jan.", "Feb." ,"Mar." ,"Apr." ,"May" ,"Jun.",
"Jul.", "Aug.", "Sept.", "Oct.", "Nov.", "Dec."
};
/* パラメータをチェック */
if (month < 1) {
month = 1;
} else if (month > 12) {
month = 12;
}
/* 月を1減じ,0オリジンに */
month--;
/* 月名称と略称を出力 */
*name = monthName[month];
*abbreviation = monthAbbreviation[month];
}
/*
month.c
月の番号から月の名称と略称を表示するプログラム
*/
/* インクルードヘッダ */
#include <stdio.h>
#include <stdlib.h>
プログラムの概略コメントとインクルードヘッダの宣言です。
/* プロトタイプ宣言 */
void getMonthName(int month, char **name, char **abbreviation);
月名称取得関数のプロトタイプ宣言です。第2引数と第3引数がポインタのポインタになっています。
/*
メイン
*/
int main(int argc, char *argv[])
{
int n;
char *nameString = NULL;
char *abbreviationString = NULL;
/* 引数のチェック */
if (argc != 2) {
printf("Usage: %s <month number>¥n", argv[0]);
return 0;
}
/* 引数を取得,atoi()でintに変換 */
n = atoi(argv[1]);
main()の冒頭部分です。コマンドラインからの引数をチェック後、指定された月をint型に変換し、変数nに格納しています。
/* 番号から月の名称を取得 */
getMonthName(n, &nameString, &abbreviationString);
月名称取得関数をコールします。第1引数が月を表す番号です。第2引数は、charのポインタであるnameString変数のアドレスです。第3引数は、charのポインタであるabbreviationString変数のアドレスです。
nameStringに月名称文字列へのポインタが格納されてきます。また、abbreviationStringに月略称文字列へのポインタが格納されてきます。
月名称取得関数を見てみましょう。
/*
月名称取得
getMonthName
<概要>
指定された月の名称と略称を出力する
<戻り値>
void
<引数>
int month:(i) 月.1なら1月,2なら2月...
char **name:(o) 月名称文字列へのポインタ
char **abbreviation:(o) 月略称文字列へのポインタ
<補足>
指定された月が1未満なら1月とみなし12を超えるなら12月とみなす。
*/
void getMonthName(int month, char **name, char **abbreviation)
{
charのポインタであるnameString変数のアドレスをnameというポインタのポインタで受け取ります。また、abbreviationString変数のアドレスをabbreviationというポインタのポインタで受け取ります。
/* 月名称 */
static char *monthName[] = {
"January", "February" ,"March" ,"April" ,"May" ,"June",
"July", "August", "September", "October", "November", "December"
};
/* 月略称 */
static char *monthAbbreviation[] = {
"Jan.", "Feb." ,"Mar." ,"Apr." ,"May" ,"Jun.",
"Jul.", "Aug.", "Sept.", "Oct.", "Nov.", "Dec."
};
月名称テーブルと月略称テーブルです。monthName配列、monthAbbreviation配列には各文字列定数へのポインタが格納されます。
/* パラメータをチェック */
if (month < 1) {
month = 1;
} else if (month > 12) {
month = 12;
}
/* 月を1減じ,0オリジンに */
month--;
範囲外の値がパラメータに渡されてくるかもしれませんのでチェックします。その後、monthから1を引きます。配列の先頭の添え字が0だからです。
/* 月名称と略称を出力 */
*name = monthName[month];
*abbreviation = monthAbbreviation[month];
}
月名称と略称を出力します。nameはmain()のnameString変数のアドレスですから、nameString変数に月名称配列に格納されている文字列定数へのポインタを入れるために*nameにmonthName[month]を代入します。
同様にabbreviationはmain()のabbreviationString変数のアドレスですから、abbreviationString変数に月略称配列に格納されている文字列定数へのポインタを入れるために*abbreviationにmonthAbbreviation[month]を代入します。
そしてmain()へ戻ります。
/* 取得した月名称と略称を出力 */
printf("%s¥n%s¥n", nameString, abbreviationString);
return 0;
}
nameStringに月名称文字列へのポインタ、abbreviationStringに月略称文字列へのポインタが格納されてきますので、それらをprintf()を使って出力します。