如何将句容建设局网站转型为专注于面食的在线平台?

摘要:句容建设局网站,做面食网站,广西南宁网站建设哪家好,北京汉邦未来网站建设有限公司指针是 C 语言最重要的概念之一,也是最难理解的概念之一。指针是C语言的精髓,要想掌握C语言就需
句容建设局网站,做面食网站,广西南宁网站建设哪家好,北京汉邦未来网站建设有限公司指针是 C 语言最重要的概念之一#xff0c;也是最难理解的概念之一。 指针是C语言的精髓#xff0c;要想掌握C语言就需要深入地了解指针。 指针类型在考研中用得最多的地方#xff0c;就是和结构体结合起来构造结点(如链表的结点、二叉树的结点等)。 本章专题脉络 1、指针… 指针是 C 语言最重要的概念之一也是最难理解的概念之一。 指针是C语言的精髓要想掌握C语言就需要深入地了解指针。 指针类型在考研中用得最多的地方就是和结构体结合起来构造结点(如链表的结点、二叉树的结点等)。 本章专题脉络 1、指针的理解与定义 1.1 变量的访问方式 计算机中程序的运行都是在内存中进行的变量也是在内存中分配的空间且不同类型的变量占用不同大小的空间。那如何访问内存中变量存储的数据呢有两种方式直接访问和间接访问。直接访问直接使用变量名进行的访问以前的程序中都是采用这种方式。 int num1  10; int num2  20; int num3  num1  num2;间接访问通过指针来实现。下面看如何理解指针。 1.2 内存地址与指针 为了能够有效的访问到内存的每个单元(即一个字节)就给内存单元进行了编号这些编号被称为该内存单元的地址。因为每个内存单元都有地址所以变量存储的数据也是有地址的。 int num  5;通过地址能找到所需的变量单元可以说地址指向该变量单元将地址形象化地称为“指针”。即 变量命名的内存空间用于存放各种类型的数据。 变量名变量名是给内存空间取的一个容易记忆的名字。 变量值在变量单元中存放的数据值。 变量的地址变量所使用的内存空间的地址即指针。 指针变量一个变量专门用来存放另一变量在内存中数据的地址 (即指针)则它称为“指针变量”。我们可以通过访问指针变量达到访问内存中另一个变量数据的目的。(有时为了阐述方便将指针变量直接说成指针。) 上图中地址0x00000001是变量 i 的指针i_pointer就是一个指针变量。 体会指针就是内存地址使用指针访问变量就是直接对内存地址中的数据进行操作。 1.3 指针变量的定义 一般格式 数据类型 *指针变量名 [初始地址值];数据类型是指针变量所指向变量数据类型。可以是 int、char、float 等基本类型也可以是数组等构造类型。 字符 * 用于告知系统这里定义的是一个指针变量通常跟在类型关键字的后面。比如 char * 表示一个指向字符的指针 float * 表示一个指向 float 类型的值的指针。此外还有指向数组的指针、指向结构体的指针。 举例1 int *p;  //读作指向int的指针”或简称“int指针”这是一个指针变量用于存储int型的整数在内存空间中数据的地址。 变形写法 int* p; int * p;注意 1、指针变量的名字是 p不是*p。 2、指针变量中只能存放地址不要将一个整数或任何其它非地址类型的数据赋给一个指针变量。 举例2同一行声明两个指针变量 // 正确 int * a, * b; // 错误 int* a, b;   //此时a是整数指针变量而b是整数变量举例3一个指针指向的可能还是指针这时就要用两个星号 ** 表示。(后面讲) int **foo;1.4 指针的应用场景 场景1使用指针访问变量或数组的元素。 场景2应用在数据结构中。比如 2、指针的运算 指针作为一种特殊的数据类型可以参与运算但与其他数据类型不同的是指针的运算都是针对内存中的地址来实现的。 2.1 取址运算符 取址运算符使用“”符号来表示。作用取出指定变量在内存中的地址其语法格式如下 变量举例1 int num  10;  printf(num  %d\n, num); // 输出变量的值。 num  10 printf(num  %p\n, num); // 输出变量的内存地址。num  00000050593ffbbc说明 1、在输出取址运算获得的地址时需要使用“%p”作为格式输出符。 2、这里num的4个字节每个字节都有地址取出的是第一个字节的地址较小的地址。 举例2将变量的地址赋值给指针变量 int num  10; int *p; //p为一个整型指针变量 p  num; 举例3 int d  10; int *e, *f; e  d; f  e;指针变量的赋值 1、指针变量中只能存放地址指针不要将一个整数或任何其它非地址类型的数据赋给一个指针变量。 2、C语言中的地址包括位置信息(内存编号或称纯地址)和它所指向的数据的类型信息即它是“带类型的地址”。所以一个指针变量只能指向同一个类型的变量不能抛开类型随意赋值。 char* 类型的指针是为了存放 char 类型变量的地址。 short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放 int 类型变量的地址。 3、在没有对指针变量赋值时指针变量的值是不确定的可能系统会分配一个未知的地址此时使用此指针变量可能会导致不可预料的后果甚至是系统崩溃。为了避免这个问题通常给指针变量赋初始值为0(或NULL)并把值为0的指针变量称为空指针变量。 举例4通过指针变量修改指向的内存中的数据 int main() {int num  10, *ptr;ptr  num;printf(%d\n,num);scanf(%d, ptr); //等价于scanf(%d, num);printf(%d\n,num);return 0; }2.2 取值运算符* 在C语言中针对指针运算还提供了一个取值运算符使用“*”符号表示。其作用与相反根据一个给定的内存地址取出该地址对应变量的值。也称为解引用符号。其格式如下 *指针表达式其中“*”不同于定义指针变量的符号这里是运算符。“指针表达式”用于得到一个内存地址与“*”结合以获得该内存地址对应变量的值。 举例1 int main() {int a  2024;int *p;p  a;printf(%p\n,a); //0000005cc43ff6d4printf(%p\n,p);  //0000005cc43ff6d4printf(%d\n, *p); //2024return 0; }举例2 int main() {int num  10; //这里定义一个整型变量numprintf(num  %d\n, num); //输出变量num的值。输出num  10printf(num  %p\n, num); //输出变量num的地址。输出num  000000e6a11ffa1cint *p  num;printf(%p\n,p); //000000e6a11ffa1cprintf(%d\n,*p);//10printf(*num  %d\n, *num);//通过num地址读取num中的数据。输出*num  10return 0; }运算符与 * 运算符互为逆运算下面的表达式总是成立 int i  5; if (i  *(i)) // 正确举例3通过指针变量修改指向内存地址位置上的值 int main() {int num  10;int *p  num;*p  20;printf(num  %d\n,num);  //num  20char ch  w;char* pc  ch;*pc  s;printf(ch  %c\n, ch); //ch  sreturn 0; }举例4 定义指针变量 p1、p2默认各自指向整数a、ba、b从键盘输入。设计程序使得 p1 指向其中的较大值p2 指向其中的较小值 。 int main() {int *p1, *p2, *p, a, b;printf(请输入两个整数: );scanf(%d,%d, a, b);p1  a;p2  b;if (a  b) {p  p1;p1  p2;p2  p;}printf(输出p1、p2: );printf(%d,%d\n, *p1, *p2);return 0; }举例5已有代码如下 int a  10; int *p; p  a;请看问题 问题1*p的含义是什么? “”和“*”两个运算符的优先级别相同但按自右而左方向运算。因此*p与a相同即变量a的地址。 如果有p1 *p; 它的作用是将a (a的地址)赋给p1 如果p1原来指向 b经过重新赋值后它已不再指向b了而指向了a。 问题2*a的含义是什么? 先进行a运算得a的地址再进行*运算。*a和*p的作用是一样的它们都等价于变量a。即*a与 a 等价。 2.3 指针的常用运算 指针本质上就是一个无符号整数代表了内存地址。除了上面提到的取址运算外指针还可以与整数加减、自增自减、同类指针相减运算等。但是规则并不是整数运算的规则。 2.3.1 指针与整数值的加减运算 格式指针±整数 指针与整数值的加减运算表示指针所指向的内存地址的移动加向后移动减向前移动。指针移动的单位与指针指向的数据类型有关。数据类型占据多少个字节每单位就移动多少个字节。 通过此操作可以快速定位你要的地址。 short *s; s  (short *) 0x1234; printf(%hx\n, s  1); //0x1236   复习%hx 十六进制 short int 类型 printf(%hx\n, s - 1); //0x1232int *i; i  (int *) 0x1234; printf(%x\n, i  1); //0x1238    复习%x 十六进制整数说明s 1 表示指针向内存地址的高位移动一个单位而一个单位的 short 类型占据两个字节的宽度所以相当于向高位移动两个字节。 再比如变量a、b、c、d和e都是整型数据int类型它们在内存中占据一块连续的存储区域。指针变量p指向变量a也就是p的值是0xFF12则 说明指针p1并不是地址1而是指针p指向数组中的下一个数据。比如int *pp1表示当前地址4指向下一个整型数据。 举例1 int main() {int arr[5]  {1, 2, 3, 4, 5};int *p  arr[1];printf(p的地址为%p,对应的值为%d\n, p, *p); //p1的地址为000000df21bff6e4,对应的值为2printf(p1的地址为%p,对应的值为%d\n, p  1, *(p  1)); //p11的地址为000000df21bff6e8,对应的值为3printf(p-1的地址为%p,对应的值为%d\n, p - 1, *(p - 1)); //p1-1的地址为000000df21bff6e0,对应的值为1return 0; }注意只有指向连续的同类型数据区域指针加、减整数才有实际意义。 举例2 对于长度是 N 的一维数组 a当使用指针 p 指向其首元素后即可通过指针 p 访问数组的各个元素。 其中 a[0]用 *p 表示 a[1]用*(p1)表示 a[i]用*(pi)表示 遍历数组操作如下 #include stdio.h #define LENGTH 5int main() {int arr[LENGTH]  {10,20,30,40,50};//方式1传统直接访问的方式for(int i  0;i  LENGTH;i){printf(%d ,arr[i]);}printf(\n);//方式2使用指针访问int *p  arr[0];for(int i  0;i  LENGTH;i){printf(%d ,*(pi));}return 0; }2.3.2 指针的自增、自减运算 指针类型变量也可以进行自增或自减运算如下 p 、 p-- 、 p 、--p和--在运算符章节已经讲过这里针对指针的增加或减少指的是内存地址的向前或向后移动。 针对于数组来说由于数组在内存中是连续分布的。 当对指针进行时指针会按照它指向的数据类型字节数大小增加比如 int * 指针每 一次 就增加4个字节。 当对指针进行--时指针会按照它指向的数据类型字节数大小减少比如 int * 指针每 -- 一次 就减少4个字节。 举例1 int main() {int arr[5]  {1, 2, 3, 4, 5};int *p1  arr[0];int *p2  arr[3];printf(p1的值为%d\n, *p1);        //1printf(p1的值为%d\n, *(p1));  //2printf(p1的值为%d\n, *p1);        //2printf(p1的地址为%p\n, p1);      //00000055c0bff704printf(p1的地址为%p\n, p1);  //00000055c0bff708printf(p2的值为%d\n, *p2);       //4printf(--p2的值为%d\n, *(--p2)); //3printf(p2的值为%d\n, *p2);       //3return 0; }举例2请分析下面几种情况。 初始情况 int a[5]  {10,20,30,40,50};情况1 int *p  a;  //p开始时指向数组a的首元素    等同于 int *p  a[0];p; //使p指向下一元素a[1] printf(%d\n,*p); //得到下一个元素a[1]的值即20情况2 int *p  a;  //p开始时指向数组a的首元素printf(%d\n,*p); //10   分析由于和*同优先级结合方向自右而左因此它等价于*(p) printf(%d\n,*p);   //20拓展 *(p); //先取*p值然后使p自增1 *(p); //先使p自增1再取*p拓展如果 p 当前指向 a 数组中第 i 个元素a[i]则 *(p--) //相当于a[i--]先对p进行“*”运算再使p自减 *(p) //相当于a[i]先使p自加再进行“*”运算 *(--p) //相当于a[--i]先使p自减再进行“*”运算情况3 int *p  a[2];  //p开始时指向数组a的第3个元素 printf(%d\n,*(p--)); //30p  a[2]; printf(%d\n,*(p)); //40p  a[2]; printf(%d\n,*(--p)); //20情况3 int *p  a;            //p开始时指向数组a的首元素 printf(%d\n,(*p)); //11/* 分析表示p所指向的元素值加1如果pa, 则相当于a[0]若a[0]的值为10则a[0]的值为11。 注意: 是元素a[0]的值加1而不是指针p的值加1 */2.3.3 同类指针相减运算 格式指针 - 指针 相同类型的指针允许进行减法运算返回它们之间的距离即相隔多少个数据单位注意非字节数。高位地址减去低位地址返回的是正值低位地址减去高位地址返回的是负值。 返回的值属于 ptrdiff_t 类型这是一个带符号的整数类型别名具体类型根据系统不同而不同。这个类型的原型定义在头文件 stddef.h 里面。 举例1 int main() {short *ps1;short *ps2;ps1  (short *) 0x1234;ps2  (short *) 0x1236;ptrdiff_t dist  ps2 - ps1;printf(%d\n, dist); // 1   相差2个字节正好存放1个 short 类型的值。int *pi1;int *pi2;pi1  (int *) 0x1234;pi2  (int *) 0x1244;ptrdiff_t dist1  pi2 - pi1;printf(%d\n,dist1);  //4   相差16个字节正好存放4个 int 类型的值。return 0; }举例2 int main() {int arr[5]  {1, 2, 3, 4, 5};int *p1  arr[0];int *p2  arr[3];printf(p1的地址为%d\n, p1); //497022544printf(p2的地址为%d\n, p2); //497022556printf(p2-p1%d\n, p2 - p1); //3 等同于 (497022556 - 497022544)/4  3return 0; }体会两个指针相减通常两个指针都是指向同一数组中的元素才有意义。结果是两个地址之差除以数组元素的长度。不相干的两个变量的地址通常没有做减法的必要。 举例 int main() {int i  10;int j  20;int *p1  i;int *p2  j;ptrdiff_t dist  p1 - p2;printf(%d\n,dist);   //通常没有计算减法的必要return 0; }非法同类指针相加运算 两个指针进行加法是非法的所得结果是没有意义的。 int i  10,j  20; int *p1  i; int *p2  j; int *p3  p1  p2; //非法2.3.4 指针间的比较运算 指针之间的比较运算比如 、! 、、 、 、 。比较的是各自的内存地址的大小返回值是整数 1 true或 0 false。 举例 int arr[5]  {1, 2, 3, 4, 5}; int *p1  arr[0]; int *p2  arr[3];printf(%d\n,p1  p2);  //0 printf(%d\n,p1  p2);  //1 printf(%d\n,p1  p2); //0 printf(%d\n,p1 ! p2); //1练习 int main() {int arr[]  {10, 20, 30};int *ptr;ptr  arr;  //ptr指向arr首地址(第一个元素)if (ptr  arr[0]) { //错误,类型不一样printf(ok1\n);}if (ptr  arr[0]) { // 可以printf(ok2\n); //输出}if (ptr  arr) { //可以printf(ok3\n); //输出}if (ptr  arr[1]) { //可以比较,但是返回falseprintf(ok4\n);//不会输出}if (ptr  arr[1]) { //可以比较,返回trueprintf(ok5\n);//输出}return 0; }【华南理工大学2018研】若有说明int *pm5n以下正确的程序段是  。 A pn;   scanf(%d,n); B pn;   scanf(%d,*p); C scanf(%d,n);   pn D pn;   *pn; 【答案】D 【解析】scanf语句中第二个参数应该是变量的地址AB错误C中p为指针变量不可以直接把一个int型变量赋值给指针型C错误答案选D。 【华南理工大学2018研】若有定义int *p*sc且各变量已正确赋值则非法的赋值表达式是 。 Aps Bc*s C*sp Dpc 【答案】C 【解析】C中p为指针变量则p表示的是指针的地址若要赋值则左边变量应该是一个二级指针而*s代表的是s所指向地址的变量值这个变量是一个int型显然不正确。 【中央财经大学2018研】有如下说明 int a[10]{1,2,3,4,5,6,7,8,9,10}, *pa;则数值为9的表达式是  。 A*p9 B*(p8) C*p 9 Dp8 【答案】B 【解析】A中*p1*p910A错误。C中*p得到的是1加9后结果是10C错误。D中p是地址p8仍然表示一个地址。因此B项正确p8指向元素9进行取值得9。 3、野指针 3.1 什么是野指针 野指针就是指针指向的位置是不可知随机性不正确没有明确限制的。 3.2 野指针的成因 ① 指针使用前未初始化 指针变量在定义时如果未初始化其值是随机的此时操作指针就是去访问一个不确定的地址所以结果是不可知的。此时p就为野指针。 int main() {int *p;printf(%d\n,*p);return 0; }在没有给指针变量显式初始化的情况下一系列的操作(包括修改指向内存的数据的值)也是错误的。 #includestdio.h int main(){int* p;                       *p  10;  return 0; }拓展注意如下的赋值操作也是错误的 int main() {int num  10;int *p;p  num;return 0; }② 指针越界访问 #include stdio.hint main() {int arr[10]  {0};int *p  arr;for (int i  0; i  10; i,p) {*p  i;                   //i10时越界}return 0; }当i10时此时*p访问的内存空间不在数组有效范围内此时*p就属于非法访问内存空间p为野指针。 ③ 指针指向已释放的空间 #include stdio.hint *test() {int a  10;return a;          //a0x0012ff40 }int main() {int *p  test();printf(%d, *p);return 0; }调用test函数将返回值赋给ptest函数的返回值是局部变量a的地址。由于a只在test函数内有效出了test函数其内存空间就被释放也就意味着a的地址编号不存在若将其赋值给p导致p获取到的地址是无效的。 如果短时间内再次利用这块地址它的值还未被改变也就是0x0012ff40还存在p的值为0x0012ff40*p时还是10可以打印出。 但如果在打印之前有其他函数调用了这块地址这块地址的名称就会发生变化不再是0x0012ff40打印*p时不再为10。 总之此时p为野指针。 3.3 野指针的避免 1、指针初始化 定义指针的时候如果没有确切的地址赋值为指针变量赋一个 NULL 值是好的编程习惯。即 int *p  NULL;赋为 NULL 值的指针被称为空指针NULL 指针是一个定义在标准库 stdio.h中的值为零的常量 #define NULL 0 后面如果用到指针的话再让指针指向具有实际意义的地址然后通过指针的取值符号(*)改变其指向的内容。 练习 #includestdio.hint main() {int *p  NULL; //空指针不要与未初始化的指针混淆int b  8;p  b;   //显式赋值*p  100;printf(%d\n, *p);  //100printf(%d\b, b);   //100return 0; }2、小心指针越界 3、避免返回局部变量的地址 4、指针指向空间释放及时置NULL int a  10;    int* pa  a; printf(%d\n, *pa);pa  NULL;    //把pa指针置成NULLprintf(%d\n,pa);5、指针使用之前检查有效性 if (pa ! NULL){//进行使用 }if (pa  NULL){//不进行使用 }4、二级指针(多重指针) 一个指针p1记录一个变量的地址。由于指针p1也是变量自然也有地址那么p1变量的地址可以用另一个指针p2来记录。则p2就称为二级指针。 简单来说二级指针即一个指针变量的值是另外一个指针变量的地址。通俗来说二级指针就是指向指针的指针。 格式 数据类型 **指针名;举例1 int a  10; int *pa  a;  //pa是一级指针 int **ppa  pa; //ppa是二级指针类型为int **进而推理会有int ***pppa ppa; 等情况但这些情况一般不会遇到。 在上述代码基础上 int b  20; ppa  b; //报错将 ppa类型为 int **即二级指针赋值为 b但 b是一个 int * 类型的指针而不是 int ** 类型。这会导致类型不匹配的错误。 如果您想要将 ppa 指向 b可以找一个额外的一级指针作为中介。如下操作 int b  20; int *pb  b;     // 使用一级指针来指向b ppa  pb;        // 将ppa指向pb的地址ppa是二级指针举例2 int main() {int var  3000;int *ptr  var;        // 一级指针指向 varint **pptr  ptr;      // 二级指针指向 ptrint ***ppptr  pptr;   // 三级指针指向 pptrprintf(Value of var: %d\n, var);printf(Value of ptr: %d\n, *ptr);         // 解引用一次printf(Value of pptr: %d\n, **pptr);      // 解引用两次printf(Value of ppptr: %d\n, ***ppptr);   // 解引用三次return 0; }举例3使用malloc()函数创建二维数组 malloc()函数用于动态分配堆内存free()函数用于释放堆内存。这两个函数通常都是配合一起使用的。 #include stdio.h #include stdlib.hint main() {int rows, cols;// 定义二维数组的行和列printf(第一维为);scanf(%d, rows);printf(第二维为);scanf(%d, cols);int **array  (int **) malloc(sizeof(int *) * rows);//先创建第一维for (int i  0; i  rows; i) {//在内层循环中动态创建第二维array[i]  (int *) malloc(sizeof(int) * cols);//for (int j  0; j  cols; j) {array[i][j]  1;printf(%d , array[i][j]);}printf(\n);}free(array);return 0; }5、专题指针与数组 复习 *也称为解引用符号其作用与相反。 *后面只能跟指针(即地址)或指针变量后面跟的是普通变量(包括指针变量)。 5.1 一维数组与指针 5.1.1 指向一维数组的指针变量 所谓数组元素的指针就是数组元素的地址。可以用一个指针变量指向一个数组元素。 int a[10]{2,4,6,8,10,12,14,16,18,20};  int *p; //定义p为指向整型变量的指针变量 p  a[0]; //把a[0]元素的地址赋给指针变量p如下几个写法是等价的 int *p; p  a[0];  //千万不要写成*p  a[0];那就错了int *p  a[0];int *p  a; //a不代表整个数组所以这里不是将数组a赋给p。而代表数组元素a[0]的首地址。注意 因为数组名a保存的是数组首元素a[0]的地址所以在scanf函数中的输入项如果是数组名不要再加地址符。 int main() {char arr[10];scanf(%s, arr);  //arr前不应加 puts(arr);return 0; }5.1.2 使用指针访问数组的元素 如果指针变量p的初值为a[0]则 pi和ai就是数组元素a[i]的地址。或者说它们指向a数组序号为i的元素。 *(pi)或*(ai)是pi或ai所指向的数组元素的值即a[i]的值。 举例1数组元素赋值、遍历 方式1下标法 #include stdio.h #define N 5int main() {int a[N];printf(请输入%d个整数\n,N);for (int i  0; i  N; i)scanf(%d, a[i]); //数组元素用数组名和下标表示for (int i  0; i  N; i)printf(%d , a[i]);printf(\n);return 0; }方式2 #include stdio.h #define N 5int main() {int a[N];printf(请输入%d个整数\n,N);for (int i  0; i  N; i)scanf(%d, a[i]); //数组元素用数组名和下标表示for (int i  0; i  N; i)printf(%d , *(a  i));printf(\n);return 0; }方式3使用指针变量 #include stdio.h#define N 5int main() {int a[N];int *p  a;printf(请输入%d个整数\n, N);for (int i  0; i  N; i)scanf(%d, p  i);for (int i  0; i  N; i)printf(%d , *(p  i));printf(\n);return 0; }或者 #include stdio.h#define N 5int main() {int a[N];int *p  a;printf(请输入%d个整数\n, N);for (int i  0; i  N; i)scanf(%d, p  i);for (p  a; p  (a  N); p)printf(%d , *p);printf(\n);return 0; }第(1)和第(2)种方法执行效率是相同的。C编译系统是将a[i]转换为*(ai)处理的即先计算元素地址。因此用第(1)和第(2)种方法找数组元素费时较多。 第(3)种方法比第(1)、第(2)种方法快用指针变量直接指向元素不必每次都重新计算地址像p这样的自加操作是比较快的。这种有规律地改变地址值(p)能大大提高执行效率。但第(1)方法比较直观适合初学者。 思 考 可以通过改变指针变量p的值指向不同的元素。如果不用p变化的方法而用数组名a变化的方法例如用a行不行呢 不行 for(p  a;a  (p  N);a)printf(%d,*a);因为数组名a代表数组的首地址或数组首元素的地址它是一个指针型常量它的值在程序运行期间是固定不变的。所以a是无法实现的。必须将 a 的地址赋值给指针变量 p 然后对 p 进行自增。 举例2获取数组的最大值 #includestdio.h #define N 5int main() {int a[N];int *p;p  a;printf(请输入%d个数据\n, N);for (int i  0; i  N; i)scanf(%d, p  i);//获取最大值int max  *p;for (int i  1; i  N; i)if (max  *(p  i))max  *(p  i);printf(Max: %d\n, max);return 0; }5.1.3 指针带下标的使用 指向数组元素的指针变量也可以带下标如p[i]。p[i]被处理成*(pi)如果p是指向一个整型数组元素a[0]则p[i]代表a[i]。但是必须弄清楚p的当前值是什么如果当前p指向a[3]则p[2]并不代表a[2]而是a[32]即a[5]。 举例 int main() {int a[5]  {10,20,30,40,50};int *p  a;//遍历数组元素for(int i  0;i  5;i){printf(%d ,p[i]);}printf(\n);//注意p;printf(%d ,p[0]); //20return 0; }5.1.4 数组名 举例1 //复习 int main() {int arr[5]  {0};int *p  arr;printf(%p\n,p);  //000000000034fa50printf(%p\n,p); //000000000037fbd8return 0; }进一步思考 printf(%p\n, arr);  //000000000034fa50 printf(%p\n, arr); //000000000034fa50发现数组名 和 数组名 打印的地址是一样的。 举例2 #include stdio.hint main() {int arr[5]  {0};printf(arr  %p\n, arr);        //000000cade5ff750printf(arr %p\n, arr);       //000000cade5ff750printf(arr1  %p\n, arr  1);    //000000cade5ff754printf(arr1 %p\n, arr  1);   //000000cade5ff764return 0; }arr 理解为数组的地址而不要理解为数组首元素a[0]的地址。 本例中 arr 的类型是 int(*)[5] 是一种数组指针类型。数组的地址1跳过整个数组的大小所以 arr1 相对于 arr 的差值是20。 【北京航空航天大学2018研】若有以下变量的声明语句 int i  1,a[]  {0,2,4}, *b; b  i;则下列选项中其结果与表达式“*(a1)”相等的是 。 Aa[0] B*ai C*(ab) D*(a*b) 【答案】D 【解析】 a指向数组的首元素因此*(a1) 表示取数组第二个元素的值为2。 A项a[0]0不相等 B项*a为数组第一个元素的值为0再加上i1因此结果为1不相等 C项a和b都是指针相加没有意义错误 D项*b的值i的值即1*(a1) 表示取数组第二个元素的值为2相等因此答案选D。