解读:《C语言解惑》中的难解的指针

来源:互联网 发布:淘宝装修日记论坛 编辑:程序博客网 时间:2024/04/29 08:55

       在C语言中,指针和数组有着千丝万缕的关系,也是很核心的内容之一,同时也是最难理解的部分。在 《C语言解惑》一书中有一道关于指针的题目,作者说只要能正确地解答之,便说明已经全面地掌握了C语言中指针的用法。

让我们先看看源代码:

int main()  {        char * c[] = {          "ENTER",          "NEW",          "POINT",          "FIRST"      };            char ** cp[] = { c + 3, c + 2, c + 1, c };      char *** cpp = cp;        printf("%s  \n",* * ++cpp );      printf("%s  \n",* -- * ++cpp + 3 );           printf("%s \n",* cpp[ -2 ] + 3 );      printf("%s  \n", cpp[ -1 ][ -1 ] +1 );        int i;      scanf("%d",&i);        return 0;  }  

在看结果之前,最好能够静下心来做一做。

运行结果:



为了能够较为明了地分析,将源代码改为如下:


#include<stdio.h>    char * c[] = {          "ENTER",          "NEW",          "POINT",          "FIRST"      };            char ** cp[] = { c + 3, c + 2, c + 1, c };      char *** cpp = cp;  int main()  {            printf( "------------START_111----------\n");      Printf();    //    输出一      printf( "------------END_111----------\n");             ++ cpp;         printf("  %s  \n",* *cpp );         printf( "------------START_222----------\n");       Printf();    //输出二       printf( "------------END_222----------\n");                ++cpp;         printf( "------------START_333----------\n");       Printf();   //输出三       printf( "------------END_333----------\n");         -- * cpp;           printf("  %s  \n",* * cpp + 3 );         printf( "------------START_444----------\n");       Printf();  //输出四       printf( "\n------------END_444----------\n");                   printf("\n\ncpp[ - 2 ] = %x  ,  * cpp[ -2 ] = %x, * cpp[ -2 ] + 3 = %x\n",                  cpp[ - 2 ],  * cpp[ -2 ], * cpp[ -2 ] + 3 );      printf("* cpp[ -2 ] + 3  =  %s \n",* cpp[ -2 ] + 3 );        printf("\n\ncpp[ - 1 ] = %x  ,  cpp[ -1 ][ - 1] = %x, cpp[ -1 ][ - 1] + 1 = %x\n",                  cpp[ - 1 ],  cpp[ -1 ][ - 1], cpp[ -1 ][ - 1] + 1 );      printf(" cpp[ -1 ][ -1 ] +1 = %s  \n", cpp[ -1 ][ -1 ] +1 );      int i;      scanf("%d",&i);        return 0;  }  


其中Printf函数代码如下:


void Printf(){printf( "cpp =  %x;        &cpp = %x;        *cpp = %x ;\n\n",  cpp , &cpp, *cpp );printf( "cp =  %x;         &cp = %x;         *cp = %x; \n\n",  cp , &cp, *cp );printf( "cp+1 =  %x;       &cp+1 = %x;       *(cp+1) = %x; \n\n",      cp + 1 ,  &cp + 1 , * ( cp + 1 ) );printf( "cp+2 =  %x;       &cp+2 = %x;       *(cp+2) = %x; \n\n",      cp + 2 ,  &cp + 2 , * ( cp + 2 ) );printf( "cp+3 =  %x;       &cp+3 = %x;       *(cp+3) = %x; \n\n",      cp + 3 ,  &cp + 3 , * ( cp + 3 ) );printf( "c =  %x;          &c = %x;          *c = %x; \n\n",      c ,  &c , *c );printf( "c+1 =  %x;       &c+1 = %x;        *(c+1) = %x; \n\n",      c + 1 ,  &c + 1 , * ( c + 1 ) );printf( "c+2 =  %x;       &c+2 = %x;        *(c+2) = %x; \n\n",      c + 2 ,  &c + 2 , * ( c + 2 ) );printf( "c+3 =  %x;      &c+3 = %x;         *(c+3) = %x; \n\n",      c + 3 ,  &c + 3 , * ( c + 3 ) );printf("ENTER  :  %x  :  %s  \n", c[ 0 ], c[ 0 ] );printf("NEW    :  %x  :  %s  \n", c[ 1 ], c[ 0 ] );printf("POINT  :  %x  :  %s  \n", c[ 2 ], c[ 2 ] );printf("FIRST  :  %x  :  %s  \n", c[ 3 ], c[ 3 ] );}



改变为以上形式是为了清楚地看到地址。

运行结果如下图:

截图一:



截图二




截图三:




截图四:




为了对比方便,故以以上方式截图。

图的说明:

    共有四个输出位于START_111和END_111,START_222和END_222,START_333和END_333,START_444和END_444之间。为了对比方便,在截图一中的START_222和END_222间的内容与截图二中的START_222和END_222间的内容完全一样,只不过在截图时对START_222和END_222间的内容截了两次,截图二与截图三中的START_333和END_333的内容也一样。

为了更精确地说明,画如下包含地址的图:

START_111和END_111的内容如下图:





START_222和END_222的内容如下图:





START_333和END_333的内容如下图:





START_444和END_444的内容如下图:




说明:

    上面的图中,cpp表示变量名,用 int i = 0;来类比,cpp相当于i,cpp的地址78020相当于&i,而其中的内容78018(对于地址图四)相当于0;但是cp和c不同,它们都是数组名,是常量。