在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不同,它们都是数组名,是常量。