Bootstrap

C语言——指针初阶(二)

本节主要对C语言——指针初阶(一)的一些内容进行补充,并主要讲解数组指针。

一.补充(易错点重点)

① 为了表示指针变量和它所指向的变量之间的联系,在程序中用“ * ”符号表示“指向”。若已定义i_pointer为指针变量,则* i_pointeri_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是一个指针数组,先通过索引访问数组中的指针,再解引用这个指针。

总结:

(int (*pt)[3]) 数组的地址(数组至少二维)
(int *pt[3]) 地址数组(一维数组)

本期指针第二节就分享到这里~~~。

往期回顾:

C语言——海龟作图(对之前所有内容复习)-CSDN博客

C语言——指针初阶(一)-CSDN博客

C语言函数递归经典题型——汉诺塔问题_《汉诺塔问题》-CSDN博客

C语言——数组基本知识(二)-CSDN博客

C语言——数组基本知识(一)-CSDN博客

C语言——数组逐元素操作练习-CSDN博客

C语言编程练习:验证哥德巴赫猜想 进制转换 rand函数-CSDN博客

C语言——函数基本知识(三)-CSDN博客

C语言——函数基本知识(二)-CSDN博客

C语言 ——函数基本知识(一)-CSDN博客

;