一 基本概念
指针变量就是存储地址的变量,声明时为
int *p = &a;
,引用变量 a 的值赋给 b 需要先指针解引用b = *p
(此时用星号来引用该存储的地址的变量的值)。/ 指针类型的大小是固定的。%p
为输出地址值的格式控制;&
为取地址符。输出变量地址值:1
2
3
4int a = 2;
int *pzz = &a;
printf("address is %p",pzz);
printf("address is %p",&a);函数指针:
指向函数的指针,存的是函数在内存中的入口地址,函数指针如int (*compare)(int a, int b)
。实参是函数名,形参是函数指针。指针函数:
函数返回的是一个指针,如int *compare(int a, int b)
。
二 详解
举例,一些定义:
变量 c、指针变量 p;数组 name、指针数组 people。(%p %X
效果相同,前者是输出地址格式控制)。
普通变量、普通指针变量、数组变量、字符串数组变量略,详见 《C 语言疑难知识点总结》。
- 指针数组解释:
一个指针数组存放了多个字符串数组的首地址,指针数组名是这个指针数组变量自己的首地址,对其解引用是字符串数组的首地址,因为字符串数组可以直接通过其首地址引用值,所以指针数组变量解引用也是存储的字符串。等同于普通指针变量的用法。
地址(这个位置本身)需要解引用还原成值(位置上的值)。/ 如
*(people+2)[0])
,指针变量 people+2(指针数组中的第三个指针变量)存的是地址,加一个星号解引用取值(另一个存值的数组的地址),如果是字符串数组就直接是值了,但如果不是则需要再次用方框解引用取值。
- 指针数组小结:
用指针数组存若干个存了值的数组(其首地址):
想用若干数组(非字符串数组)中某个数组中的某个值时:指针数组(其中一个),解引用后变存值的数组首地址(指针数组变量存的位置上的值)-> 再次解引用变存值的数组中某个位置具体值
。用指针数组存若干个存了值的变量地址、字符串数组(其首地址):
想用变量值、字符串数组,和普通指针变量一样:指针数组(其中一个),解引用后变成变量存的位置上的值(相当于字符串数组)
。
- 小结:
基本变量、指针:
常规变量名是存的值(位置上的值)、常规指针变量名是存的某变量的地址(某个位置)。数组、指针数组:
数组变量名是它自己的首地址、指针数组变量名(相当于若干个指针变量的第一个)是它自己的首地址(这个位置本身)。/ 数组名、指针数组名相当于初始化有自己地址的指针变量。/ 方框和星号[] *
分别解引用数组、指针变量,来取这个位置上的值。字符串(数组):
(位置上的值、这个位置本身)数组的首地址可以引用其值即字符串数组,或方框星号[] *
解引用来取这个位置上的值。
三 总结
1 概念间关系
2 指针数组总结
1 | int main(void) { |
1 | /* 输出 */ |
- 指针数组、二维数组的统一:
指针数组是先有指针(一组指针变量),用指针去表示是引用值。/ 二维数组是现有数组,后将数组的一维地址赋给指针,然后用指针去引用值。/ 两者在引用值上相同,但定义初始化不同:1
2
3
4
5
6
7
8
9
10
11指针数组:
char *people[3];
char name3[10] = {'g','h','i'};
people[2] = name3;
printf(" * people[2] value is %c\n", (*(people+2))[1] );
二维数组:
char name[3][3] = {{...},{...},{'g','h','i'}};
char (*p)[4];
p = &name[0];
printf(" name[2][1] value is %c\n", (*(p+2))[1] ); // h
3 解释
指针数组存放的是指针数组(若干个指针变量)变量自己的首地址(是数组、指针两个概念的集合)。/ 指针数组名 + n 来表示组中若干个指针变量;注意,数组名相当于首地址指针常量,不能加法移动改变位置。
数组和指针类似,不同之处:数组名存放的是数组变量自己的首地址;指针存放的是其它变量的地址。
基本类型变量存放的是一个数据值。
字符串数组既类似基本变量(可以直接通过数组地址引用值,常用方法)、也是数组。
数组指针:因为数组名本质上也是指针,所以第一次解引用是从数组指针变量还原为数组名,第二次解引用是从数组名还原为具体值。