ポインタ型
ポインタ型とポインタが指す型は2つの概念です。
文法的な観点から:ポインター宣言ステートメントの場合、ポインター名を削除し、残りはポインター型です。ポインター名と前の*記号を削除し、残りはポインターが指す型です。
ポインタ宣言文 | ポインタ型 | ポインタが指すタイプ |
---|---|---|
int * p; | int * | int |
int ** p; | int ** | int * |
int(* p)[5]; | int(*)[5] | int()[5] |
int *(* p)[5]; | int *(*)[5] | int *()[5] |
メモリのセクションがあり、メモリのこのセクションに格納されているコンテンツのタイプが固定されている限り、そのセクションへのポインタを定義できます。
ポインタが指すタイプは、* pが占めるスペースを測定することで確認できますsizeof(*p)
。
1. 1次元配列へのポインター:int(* p)[10]
宣言は、pが「長さ」が10の整数配列へのポインターであることを示しています。つまり、足し算と引き算の単位は配列全体です。
2次元配列の場合:2次元配列
の操作単位は1次元配列です。したがって、一次元配列の割り当てへのポインタポイントは、直接配列名に割り当てることができる場合:int (*p)[10] = array;
(&と*逆演算であり、それはまた次のように書くことができるint (*p)[3] = &a[0];
)
割当Pが二次元アレイ缶として見た後にbe p [0] [0]このような操作ですが、pポインタが指す位置に注意してください(pが指す位置が原点として使用されます)。2次元配列として、p ++操作の単位要素は1次元配列であるため、p ++操作は次の1次元配列に切り替えることができます。(* p)は1次元配列と見なすことができます。
int a[3][3] = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
int (*p)[3] = a;
printf("%d\n", p[0][0]);//输出1
printf("%d\n", (*p)[1]);//输出2 (*p)[1]相当于a[0][1]
p ++;
printf("%d\n", (*p)[1]);//输出5 此处(*p)[1]相当于a[1][1]
printf("%d\n", (*(p+1))[1]);//输出8
printf("%d\n", *(*p+1));//输出5 *p可视作一维数组
printf("%d\n", p[0][0]);//输出4 p所指的位置不再是a[0][0]而是a[1][0],因此导致p[0][0]的值与a[0][0]不同
1次元配列の
場合:割り当て中に配列名を直接割り当てる場合、配列名は実際には最初の要素のアドレスにすぎず、ポインターは単一の配列要素のみを指します。配列全体を指すために、割り当てるときに1次元配列を「拡大」する必要があります:int (*pt)[10] = &array;
(&演算子を使用)(*演算子はより詳細になり、&演算子は反対になります)
割り当て後、pは最初の次元が0の「2次元配列」は、p [0] [1]などの操作を実行できます。(* p)は1次元配列と見なすことができます。pはすでに1次元配列全体を指しているため、p ++操作には意味がありません。
int a[9] = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
int (*p)[9] = &a;
printf("%d\n", p[0][1]);//输出2
printf("%d\n", (*p)[1]);//输出2 (*p)[1]相当于a[1]
2.機能へのポインタ
関数には、ポインタに割り当てることができる物理メモリアドレスがあります。関数の関数名は、関数のエントリポイントであるポインタです。関数は、関数名または関数へのポインターを介して呼び出すことができます。
たとえば、定義形式をint (*p)(int i, int j);
簡略化しint (*p)(int, int);
て、pが戻り値が整数であり、2つの整数パラメーターを必要とする関数を指すことを示すこともできます。定義後、ポインターに関数名を割り当てれば、(* p)を関数名として使用できます。
#include<stdio.h>
int max(int x, int y)
{
return(x > y ? x : y);
}
int main()
{
int (*p)(int, int);//定义一个指向函数的指针变量
int a, b, c;
p = max;//将函数的入口地址赋给p,此时p和max都指向函数的开头
scanf("%d%d", &a, &b);
c = (*p)(a, b);//调用*p就是调用max函数
printf("%d", c);
return 0;
}
関数へのポインタを使用すると、さまざまな状況に応じてさまざまな関数を呼び出すことができます。これは非常に便利です。
#include <stdio.h>
int max(int x, int y)
{
return(x > y ? x : y);
}
int min(int x, int y)
{
return(x < y ? x : y);
}
int main()
{
int (*p)(int, int);//定义一个指向函数的指针变量,它可以指向 函数类型为int,且有两个int型参数 的函数
int a, b, c, n;
scanf("%d%d%d", &a, &b, &n);
//函数名代表函数的入口地址(起始地址、指针)
if (n == 1) p = max;//将函数的指针赋给指针变量,只需给出函数名即可
if (n == 0) p = min;//根据输入的n的值来判断调用哪个函数
c = (*p)(a, b);//(*p)即p所指向的函数名。 表达式唯一(方便!)
printf("%d", c);
return 0;
}
なお、区別int *函数名(参数列表)
とint (*p)(参数列表)
前者定義ポインタを返す関数、関数へ後者画定するポインタ。
3.構造体へのポインタ
定義(* p)が設定された構造変数と同等になった後、作成された構造タイプの場合は、ポインターのタイプを定義するだけです。
struct Student
{
long num;
char name[20];
}s[3] = {
{
10101, "Tom"}, {
10102, "Jack"}, {
10103, "Join"}};
struct Student *p;
for (p = s; p < s + 3; p ++)//将结构体数组的地址赋给指针变量
{
printf("%ld\t%s\n", (*p).num, (*p).name);//(*p)表示p指向的结构体变量,(*p).num表示p所指向的结构体变量中的成员num
printf("%ld\t%s\n", p->num, p->name);//更加形象化地表示"指向",两种表示的效果相同
}