《指针的编程艺术(第二版)》一第三章 指针与数组3.1 指针与一维数组

    xiaoxiao2024-05-27  107

    本节书摘来自异步社区《指针的编程艺术(第二版)》一书中的第3章,第3.1节,作者 蔡明志,更多章节内容可以访问云栖社区“异步社区”公众号查看

    第三章 指针与数组

    指针的编程艺术(第二版)3-1 指针与一维数组

    3-2 指针与二维数组

    3-3 数组指针

    3-4 为什么parr等同于 *parr?

    3-5 指向数组的指针

    3-6 多重指针

    3-7 命令行参数

    3-8 改错题

    3-9 练习

    3-10 程序实战

    指针其实就是一个地址。数组的名称,表示这个数组的第1个元素的地址,所以它也是指针。由此可知,指针与数组的关系是很密切的。为了与指针变量(pointer variable){XE "指標變數(pointer variable)"}有所区别,我们称数组名就是指针常量(pointer constant){XE "指標常數(pointer constant)"}。指针变量与指针常量的不同之处在于,前者可以使用递增运算符(++)或递减运算符(--)来递增和递减指针;但后者不行。因此,如果在程序中使用arr++或arr--,就会出现错误的信息。

    3.1 指针与一维数组

    指针的编程艺术(第二版)我们先来看一下指针与一维数组(one dimension array)的关系。请参阅范例pointerArr1-5。

    范例pointerArr1-5

    /* pointerArr1-5.c */ #include <stdio.h> #include <conio.h> int main() {   int arr[]= {100, 101, 102};   int *ptr = arr;   int i, size = 0;   size = (sizeof arr/ sizeof (arr[0]) );      /* ------------Using arr--------------*/    printf("使用 arr 指针常量来表示:\n");   for(i = 0; i < size; i++)     printf("&arr[%d] = %x\n", i, &arr[i]);        printf("\n");     for(i = 0; i < size; i++)     printf("arr+%d = %x\n", i, arr+i);      printf("\n");   for(i = 0; i < size; i++)     printf("arr[%d] = %d\n", i, arr[i]);      printf("\n");   for(i = 0; i < size; i++)     printf("*(arr+%d) = %d\n", i, *(arr+i));   /*--------------Using ptr-------------*/   printf("\n使用ptr 指针变量来表示:\n");   for(i = 0; i < size; i++)     printf("ptr+%d = %x\n", i, ptr+i);   printf("\n");   for(i = 0; i < size; i++)     printf("ptr[%d] = %d\n", i, ptr[i]);   printf("\n");   for(i = 0; i < size; i++)     printf("*(ptr+%d) = %d\n", i, *(ptr+i));   getch();   return 0; }

    输出结果

    从输出结果可以知道,arr是数组名,它是指针常量,而ptr是指针变量。arr表示这个数组第1个元素的地址,也就是arr等同于&arr[0]。

    arr可以使用指针变量的符号,如arr等同于arr[0],(arr+1) 等同于arr[1],依此类推。同理,ptr也可以使用指针常量的[]符号,例如,当前ptr所指向变量地址的值为ptr[0],它等同于ptr,而ptr[1]等同于*(ptr+1),依此类推。

    再来看范例pionterArr1-10。

    范例pointerArr1-10

    /* pointerArr1-10.c */ #include <stdio.h> #include <conio.h> int main() {   int i[] = {100, 200, 300, 400, 500};   int *ptr = i+2;   int k;   printf("ptr[-2]=%d\n", ptr[-2]);   printf("ptr[-1]=%d\n", ptr[-1]);   printf("ptr[0]=%d\n", ptr[0]);   printf("ptr[1]=%d\n", ptr[1]);   printf("ptr[2]=%d\n\n", ptr[2]);      ptr++;   printf("After executing ptr++....\n");   printf("ptr[0]=%d\n", ptr[0]);   printf("*(ptr+0)=%d\n", *(ptr+0));   printf("ptr[1]=%d\n", ptr[1]);   printf("*(ptr+1)=%d\n", *(ptr+1));      getch();   return 0; }

    输出结果

    ptr与i数组的关系图如下所示。

    程序一开始将ptr指向i+2(它是i[2] 的地址),所以ptr[0] 等于i[2],因为ptr[0]表示当前ptr所指向变量地址的值。同时也知道ptr[-1] 是i[1]、ptr[-2] 是i[0]、ptr[1]是i[3]、ptr[2] 是i[4]。我们从这个范例得到以下的公式

    ptr[i] == *(ptr+i)

    大部分的用户都是用*(ptr+i)间接访问数组中索引为i的元素值。

    当指针与++递增运算符一起运算时,必须注意++的作用对象在哪里,是对地址加1,还是将变量值加1。如果是对地址加1,则将指针移到下一元素的地址。请参阅范例pointerAnd++。

    范例pointerAnd++

    /* pointerAnd++.c */ #include <stdio.h> #include <conio.h> int main() {   int i[] = {100, 200, 300, 400, 500};   int *pi = i;   printf("i=%p, pi=%p\n", i, pi);   printf("i[0]=%d\n", i[0]);   printf("*pi=%d\n\n", *pi);      pi+1;   printf("After pi+1, pi=%p\n", pi);;   printf("*pi=%d\n\n", *pi);      pi++;   printf("After pi++, pi=%p\n", pi);   printf("*pi =%d\n", *pi);   getch();   return 0; }

    输出结果

    从输出结果可知,pi+1只是将当前的pi向下移到下一个元素的地址,它并没有覆盖pi。而pi++不仅将当前的pi移到下一个元素的地址,而且还将它的新值还覆盖了pi。我们可以对指针变量pi做++的动作,但不可以对数组名i做++的动作。

    当指针、递增运算符(++){XE "遞增(++)運算子" y "ㄉㄧˋㄗㄥㄩㄣˋㄙㄨㄢˋㄗˇ"}或递减运算符(--){XE "遞減(--)運算子" y "ㄉㄧˋㄐㄧㄢˇㄩㄣˋㄙㄨㄢˋㄗˇ"},及 * 这3个运算符同时出现时,要注意++的作用点在哪里。请参阅范例pointerAnd++2。

    范例pointerAnd++2

    /* pointerAnd++2.c */ #include <stdio.h> #include <conio.h> int main() {   int i[] = {100, 200, 300, 400, 500};   int *pi = i;   printf("...%d\n", *pi++);   printf("*pi = %d\n", *pi);   printf("...%d\n", *++pi);   printf("*pi = %d\n", *pi);   printf("...%d\n", ++*pi);   printf("*pi = %d\n", *pi);   getch();   return 0; }

    输出结果

    从程序定义中

    int i[ ] = {100, 200, 300, 400, 500};  int *pi = i;

    得知,其示意图如下。

    下一条语句

    *pi++;

    当和++在同一个语句中时,要注意++的作用对象,是对地址加1还是对值加1。如果对地址加1,表示将pi指针移到下一地址。由于和++的运算优先级相同,且其结合性是由右至左,因此pi++其实就是(pi++),但这里的++为后置加,所以先得到*pi为100之后,才会处理++的动作。因此语句先输出100,再将pi指向下一个地址。如下图所示。

    接下来的

    *++pi;

    由于这条语句相当于(++pi),这里的 ++ 是前置加,所以pi指针先移到了下一个地址,再输出pi的值(300),如下图所示。

    最后

    ++*pi;

    这条语句相当于++(pi),由此可知,++是针对pi的值加1,这条语句等同于

    *pi = *pi + 1;

    将pi(= 300)加1,再放入pi中,如下图所示。

    最后,*pi的运算结果为301

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)