本节主要对C语言——指针初阶(一)的一些内容进行补充,并主要讲解数组指针。
一.补充(易错点重点)
① 为了表示指针变量和它所指向的变量之间的联系,在程序中用“ * ”符号表示“指向”。若已定义i_pointer为指针变量,则* i_pointer是i_pointer所指向的变量,因此* i_pointer也代表一个变量,它和变量i是同一回事。
下面两个语句作用相同:
(1)i=3;
(2) * i_pointer=3;
第二个语句含义是将3赋给指针变量i_pointer所指向的变量i.
② C语言提供两种有关的运算符:(1)&:取地址运算符(用来表示变量的地址)(2)*:取内容运算符(用来取其指向的内容,或称"间接 访问"运算符,或称指针运算符)两种运算符都是单目运算符,其结合性都为自右向左,优先级别相同。
例如.&a为变量a的地址, *p为指针变量o所指向的内存单元的内容 (即p所指向的变量的值)。
二.数组的指针(重点难点)
一维数组的指针
数组名指的是数组首元素的首地址。当创建数组时,编译器自动为它创建一个内部指针常量,并将数组的基址存储在该指针中。
数组名是编译器为该数组创建的指针常量。数组名是指针常量grade = &grade[2]是无效的
比如grade[]={};
那么grade=&grade[0];
若gptr是一个指针变量 gptr=&grade[0] (gPtr+3)=& Grade[0] + 3*4 ; *(gPtr+3) = grade[3];
即指针+数字=指针+数字* sizeof(所指向的数据类型)
指针+数字=指针+数字* sizeof(所指向的数据类型)
数组名不能++,因为数组名指首元素的地址是常量。
下面我们来区分一下*p++与*(p++)与(*p)++
1. **对于`*p++`和`*(p++)`这两种写法是等价的。 根据运算符优先级,后置自增`++`的优先级高于解引用`*`运算符。所以在`*p++`和`*(p++)`中,先计算`p++`。
p++`是先返回`p`的当前值,然后再将`p`的值(指针的值)加1。之后再对这个返回的(未加1之前的)`p`的值进行解引用操作`*`,所以是先取`p`指向的值,然后`p`本身加1。
例如,假设有`int a[] = {1, 2, 3}; int *p=a;`,当执行`*p++`时,首先返回`*p`(此时`*p`为1),然后`p`指向`a[1]`。
2. **对于`(*p)++`** - 首先,括号改变了运算顺序。先执行`*p`,即解引用`p`,得到`p`所指向的变量的值。 - 然后对这个解引用后的值进行后置自增操作`++`,所以是`p`所指向的值加1,而`p`本身(指针)不变。 - 例如,同样假设有`int a[] = {1, 2, 3}; int *p=a;`,当执行`(*p)++`时,`*p`(此时`*p`为1)的值加1,数组`a`的第一个元素变为2,`p`仍然指向`a[0]`。
二维数组的指针
二维数组名+1=偏移一行
此处可以这样理解,二维数组是一个二级指针,数组名指首行的地址,数组名+1指偏移一行,而*num之后对*num进行加减操作是对列进行变换。
int a[10], *p;
p = a;
*(p+i), p[i], *(a+i) 三者等价
这个图其实和上面那个表格是等价的。
下面来分析一下(*pt)[3]与*pt[3]区别
① (*pt)
表示对指针pt
进行解引用。这意味着pt
是一个指向数组(长度为 3)的指针。
比如有如下代码:
int arr[2][3] = { {1, 2, 3}, {4, 5, 6} };
int (*pt)[3];
pt = arr;
- 这里
pt
是一个指向包含 3 个整数的数组的指针。(*pt)[3]
这种写法试图访问pt
所指向的数组的第 3 个元素(索引为 2,因为数组索引从 0 开始)。在上面的例子中,(*pt)[0]
就是arr[0][0]
(值为 1),(*pt)[1]
是arr[0][1]
(值为 2),(*pt)[2]
是arr[0][2]
(值为 3)。 - 它的重点在于
pt
是指向数组的指针,先解引用得到数组,然后通过索引访问数组中的元素。 (*pt)
对pt
进行解引用,此时就相当于得到了pt
所指向的那个包含 3 个整数的数组,也就是arr
的第一行{1, 2, 3}
。- 可以这样理解,
(*pt)
让我们定位到了arr
的第一行,然后[1]
这个索引就从这一行中选取了第二个元素。 ② *pt[3]
根据运算符优先级,[]
(数组下标)运算符的优先级高于*
(解引用)运算符。所以pt[3]
先进行计算,表示pt
是一个指针数组(有 3 个指针元素),pt[3]
是访问这个指针数组中的第 3 个元素(索引为 2)。- 然后再对这个指针进行解引用操作
*
。例如:int a = 1, b = 2, c = 3; int *pt[3]; pt[0]=&a; pt[1]=&b; pt[2]=&c;
- 在这里,
*pt[3]
(假设合法访问,实际这里访问pt[3]
已经越界了,应该是0 - 2
的索引范围)首先会获取pt
数组中的第 3 个指针元素,然后对这个指针进行解引用。 - 这种写法中
pt
是一个指针数组,先通过索引访问数组中的指针,再解引用这个指针。
- 然后再对这个指针进行解引用操作
总结:
本期指针第二节就分享到这里~~~。
往期回顾:
C语言函数递归经典题型——汉诺塔问题_《汉诺塔问题》-CSDN博客