一文带你深入浅出指针和数组习题讲解

目录

🍧前言

🍧一维整型数组

🍧题目 

🍧讲解

🍧一维字符数组

🍧第一类 

🍧题目 

讲解

🍧第二类

🍧题目

🍧讲解

🍧第三类

🍧题目

🍧讲解

🍧二维数组

🍧题目

🍧讲解

🍧指针笔试题

🍧第一题

🍧题目 

🍧讲解

🍧第二题

🍧题目

🍧讲解

🍧第三题

🍧题目

🍧讲解

🍧第四题

🍧题目

🍧讲解

🍧第五题

🍧题目

🍧讲解

🍧第六题

🍧题目

🍧讲解

🍧第七题

🍧题目

🍧讲解

🍧第八题

🍧题目

🍧讲解 

🍧敬请期待更好的作品吧~


🍧前言

        在学习了数组和指针后,有可能会认为就这就这,实际上只是学了和熟练掌握还差的远呢,需要不断练习来熟悉,本文就来分享一波相关习题及个人讲解,由于作者水平有限,难免存在纰漏,读者各取所需即可。

给你点赞,加油加油!

        墙裂建议还没把数组和指针初阶、进阶学过的读者先去补一补对应知识,不然可能有些地方会一脸懵逼,下面贴上指路链接:

数组:一文带你深入浅出C语言数组http://t.csdn.cn/ScypD

指针(初阶):一文带你深入浅出C语言指针(初阶)http://t.csdn.cn/vH6LQ

指针(进阶):一文带你深入浅出C语言指针(进阶)http://t.csdn.cn/UYQOt

 

🍧一维整型数组

🍧题目 

        先看看题,想一想再看后面分析。 

int a[] = {1,2,3,4};

printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

🍧讲解

printf("%d\n",sizeof(a));

        数组名在sizeof中单独出现,代表整个数组,计算的是该数组的大小,含有四个int型变量,所以大小为16。

printf("%d\n",sizeof(a+0));

        注意一下,这里的数组名不是单独出现在sizeof中的,同时也没有取地址,结合我们在数组博文提到过的,这里a就是首元素地址,而a+0偏移量为0,被认为是int指针类型,计算得得到4或8。

        补充:我们在以前的博文中提过,地址就是指针,地址在sizeof中就是指针,计算的就是指针大小,无论什么类型的指针,在32位平台下大小为4,64位平台下大小为8。

printf("%d\n",sizeof(*a));

        a不是单独出现在sizeof中的吧,那它就代表首元素地址即&a[0],对其解引用也就相当于*&a[0],得到的不就是a[0]嘛,也就是1呀,类型是int,计算得到的大小就为4。

printf("%d\n",sizeof(a+1));

        一直重复讲有点赘余了,我就直说a在这里代表首元素地址,这里就是指针+-整数运算,顺便讲讲吧,指针+-整数,发生指针偏移,以原指针指向位置为基准、指针指向类型的变量所占大小为单位(比如int指针的偏移单位就是4字节,char[5]指针的偏移单位就是5等等)以及所加减的整数为系数,实际上是指针+-(整数*单位)。

        可能有人就会问了,那啥叫偏移呀?嘛,简单来说就是相较于原来的位置发生了移动。那既然是移动,我们可以粗略的将偏移单位看成步长(走一步的长度),这样看的话其实偏移量也就是指针这跑跑那逛逛走的路程。

        拉回正题,a在这里代表首元素地址,指针类型是啥,那看它指向的是什么类型变量,它是什么的地址呀,是int型变量的地址哦,指向的就是int类型变量,那好,步长就是4咯,a+1的话偏移量就是1*4也就是4,也就正好移动到a[1]处,所以是&a[1],是指针嘛,计算得到4或8。

         实际上指针偏移的设计是趋于容易理解和使用的方向的,如果完全不清楚指针+-整数要考虑偏移单位也问题不大,比如指针+1就是让指针跳过一个对应类型的变量,不论该类型的变量所占空间大小有多大,指针运算都是你加减多少就移动略过多少对应类型变量所占空间大小,方便对数组之类的数据结构的访问(毕竟数组一块内存中都是同类型的),自然也让人想到数组的指针表示法如*(a+1)即a[1],你细品就对了。

printf("%d\n",sizeof(a[1]));

这个就简单了,a[1]是int型,计算得到4。

printf("%d\n",sizeof(&a));

        &a取到整个数组a的地址,是指针,先甭管你是什么类型指针,反正计算得到4或8。再讨论&a就是说它类型是int(*)[4]

printf("%d\n",sizeof(*&a));

        &a取到整个数组的地址,指针类型为int(*)[4],而指针类型决定了其在解引用时的访问权限有多大,比如char*指针解引用能访问1个字节,int*指针解引用能访问4个字节,所以int(*)[4]解引用能访问int[4]类型数组,也就是说*&a就能拿到整个a数组,所以计算得到结果就是16。

        或者可以这样理解,*和&作用相反,放一起不就抵消了嘛,所以就相当于sizeof(a),因此计算结果就为16。

printf("%d\n",sizeof(&a+1));

        还记得前面刚讲的指针+-整数运算吧,那你说说这里该如何理解呀?

        &a取出整个数组的地址,指针类型是int(*)[4],所以加个1它能跳多远?算算?

         实际上一般不会一个字节一个字节地算,而是关注它的类型,加1的话就是向高地址方向跳过一个对应类型大小地空间,这是数组指针,当然是跳过一个数组,不过他仍是指针,计算得到4或8。

printf("%d\n",sizeof(&a[0]));

        这就是首元素地址,是指针,结果就为4或8。

printf("%d\n",sizeof(&a[0]+1));

        首元素地址为基准发生一个单位的偏移,也就是偏移到a[1]处,也就相当于&a[1],还是指针,结果就为4或8。(与前面讲的a+1其实一样)。

🍧一维字符数组

🍧第一类 

🍧题目 

char arr[] = {'a','b','c','d','e','f'};

printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

讲解

printf("%d\n", sizeof(arr));

        经过前面的历练,这个就显得很简单了吧,这代表整个数组,计算得到6。

printf("%d\n", sizeof(arr+0));

        emmm,没啥好说的,这里是指针,计算得到4或8。

printf("%d\n", sizeof(*arr));

        arr这里代表首元素地址,解引用就得到首元素,元素对应类型为char,所以计算得到1。

printf("%d\n", sizeof(arr[1]));

        就是数组的第2个元素,类型为char,计算得到1。

printf("%d\n", sizeof(&arr));

        取到整个数组的地址,但还是指针,计算得到4或8。

printf("%d\n", sizeof(&arr+1));

        指针,计算得到4或8(类同前面一维整型数组的)

printf("%d\n", sizeof(&arr[0]+1));

        指针,计算得到4或8(类同前面一维整型数组的)

        好了,注意一下我们接下来这几个看的都是strlen函数了。

printf("%d\n", strlen(arr));

        答案会是6吗?要不要自己在编译器试试看?

        实际上答案是随机值,为什么?

        大家了解过strlen函数吧,鉴于C中字符串以'\0'结尾,strlen在计算字符串长度的时候也是以'\0'为结束标志而不包括'\0'的。那好,arr数组中并没有放入'\0',而数组后面的空间我们不清楚到底放的是什么值,而strlen函数内会一直往后找,直到遇见'\0'结束,所以到底什么时候遇见'\0'全看命,不同编译器下结果很大可能不同,所以才说答案是随机值。

printf("%d\n", strlen(arr+0));

        指针偏移量为0,搁这原地踏步呢。

        一定要注意strlen和sizeof大有不同,strlen从传入的指针处开始计算字符串长度,而sizeof才不管你指针偏移量多少,只要你是指针就是4或8。

        这个的结果同上面那个一样的是随机值。

printf("%d\n", strlen(*arr));

        注意了!strlen函数的参数是const char*指针类型,你给它传入的值都会被认为是指针,arr代表首元素地址,所以*arr就是'a'对应值为97,也就相当于strlen(97),但是97这个地址我们有读写权限吗?

        内存空间并不是都有效可用的,我们只有权限使用系统分配给我们的地址,其余的地址一律不合法,这样的指针是野指针,我们硬要使用的话很有可能报错:访问发生冲突。

        悄悄提一嘴,实际上比较小的地址(比如上面的97之类的)是完全不能给用户使用的,是有特殊的重要的作用的。

        所以呢,这样搞会出问题,是没有答案的。

printf("%d\n", strlen(arr[1]));

        这个道理同上,我就不赘述了。

printf("%d\n", strlen(&arr));

        strlen函数的形参类型是const char*,而&arr取出整个数组地址,是char(*)[6]类型,那是不是就会出错呢?其实吧,传参是一回事,但是传入后的值被如何解释又是一回事,也就是说不管你传入的值原来是什么类型的,在传的时候只保留了值,传入后要被使用时便根据形参的类型来看待它,所以传入&arr在被使用时就是const char*类型的。

        这么说的话,因为&arr和arr在值上是一样的,所以strlen(&arr)相当于strlen(arr)。答案就是随机值。

printf("%d\n", strlen(&arr+1));

        在上面分析的基础上,这个不就是指针向后跳了一整个数组嘛,从原来字符数组的后面开始计算字符串长度,还是随机值,因为后面到底什么时候能遇到'\0'犹未可知嘛,不过可以确定的是,这个随机值要比strlen(arr)小6。

printf("%d\n", strlen(&arr[0]+1));

        这个就是从arr[1]处开始计算字符串长度,也是随机值,可以确定的是这个随机值要比strlen(arr)小1。

🍧第二类

🍧题目

char arr[] = "abcdef";

printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

🍧讲解

printf("%d\n", sizeof(arr));

        遇到" "编译器会认为是字符串,所以初始化的时候会自动在末尾加上'\0',所以数组元素个数其实是7,计算得到7。

printf("%d\n", sizeof(arr+0));

        讲到吐了有木有…

        是指针,计算得到4或8。

printf("%d\n", sizeof(*arr));

        arr不是单独出现在sizeof中,这里代表首元素地址,再解引用就得到第一个字符,类型为char,计算得到1。

printf("%d\n", sizeof(arr[1]));

        数组第二个字符,类型为char,计算得到1。

printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

        是指针,计算得到4或8。

        这些没有细讲的题其实跟前面讲第一类的题差不多的,不太理解的话回到前面看看。

        讲了这么多了,我们来巩固一下strlen和sizeof的区别吧。

        strlen是库函数,是求字符串长度的,关注的是字符串中的'\0',计算的是'\0'之前出现的字符个数。

        sizeof是操作符,只关注对应类型的变量占用内存空间的大小,而不在乎内存中放的是啥。

        继续吧,不过下面的和第一类的差不多,唯一差别就是第二类的数组多了个'\0',简单看看吧

printf("%d\n", strlen(arr));

        这回的数组就有'\0'了,所以答案是6。

printf("%d\n", strlen(arr+0));

        strlen看重的是指针指哪,加个0原地打转没影响,答案还是6。

printf("%d\n", strlen(*arr));

        arr是首元素地址,所以解引用得到的就是首字符,后面的讲解完全同前面第一类的讲过的一样,可以翻回去看看。

printf("%d\n", strlen(arr[1]));

        道理同上。

printf("%d\n", strlen(&arr));

        相较于前面第一类讲的,这个数组是带有'\0'的,所以在字符数组末尾就停下来了,答案就是6。

printf("%d\n", strlen(&arr+1));

        。。。不赘述了,答案是随机值,不清楚的翻回前面有一样的题型。

printf("%d\n", strlen(&arr[0]+1));

        从arr[1]开始计算字符串长度,答案是5。

🍧第三类

🍧题目

char *p = "abcdef";

printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));

🍧讲解

char *p = "abcdef";

         注意啦,字符串字面量(常量)在表达式中代表字符串首元素的地址。常量也有地址吗?有的,它们存储在只读常量区,也有地址。

printf("%d\n", sizeof(p));

        p就是指针,存放该字符串首元素地址,计算得到4或8。

printf("%d\n", sizeof(p+1));

        p+1偏移到下一个字符处,还是指针,计算得到4或8。

printf("%d\n", sizeof(*p));

        解引用得到第一个字符,类型是int,计算得到1。

printf("%d\n", sizeof(p[0]));

        直接就是数组第一个元素,类型为char,计算得到1。

printf("%d\n", sizeof(&p));

        要注意啦,这里是用char*指针来引用字符串的,不像前面讲的字符数组,这里的p是指针变量,也有自己的地址,这里取得就是这个指针变量的地址,其实就是二级指针,计算得到4或8。

printf("%d\n", sizeof(&p+1));

        取出的是指针变量p的地址,+1就向后偏移跳过该指针变量,仍然是指针,计算得到4或8。

printf("%d\n", sizeof(&p[0]+1));

        首先,这里是指针的数组表示法,p[0]即*(p+0),即得到首元素,所以这里取的是字符串首字符地址,再加个1就是第二个字符的地址,仍是指针,计算得到4或8。

printf("%d\n", strlen(p));

        传的是指针,指向的就是字符串(自带了'\0'),计算得到就是该字符串长度6。

printf("%d\n", strlen(p+1));

        指针向后移了一个单位,也就是计算除开第一个字符剩下的字符串,答案是5。

printf("%d\n", strlen(*p));

        p在这代表首元素的地址,解引用得到首字符,放进去就出问题,原因可以参考前面讲过的题。

printf("%d\n", strlen(p[0]));

        p[0]相当于*(p+0)即*p,所以同上。

printf("%d\n", strlen(&p));

        取出的是指针变量p的地址,所以是从p处开始往后找'\0',啥时候遇见完全是个未知数,答案就是随机值。

printf("%d\n", strlen(&p+1));

        也是随机值,但是跟 strlen(&p)的值不存在固定的关系,p的值完全不确定,同时指针变量是占四字节的,而strlen是一个字节一个字节地找'\0'的,'\0'ASCII码值就是0,无法确定p的四个字节中会不会有'\0',最少都有两种情况(有或没有'\0'),所以能借此断定它们没有必然的联系。

printf("%d\n", strlen(&p[0]+1));

        取得是p[0]的地址,再向后移动一个单位,也就是计算除开第一个字符剩下的字符串,计算得到5。

🍧二维数组

🍧题目

int a[3][4] = {0};

printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

🍧讲解

printf("%d\n",sizeof(a));

        一个道理,数组名单独放入sizeof中,代表整个数组,数组a含有12个int元素,计算得到48。

printf("%d\n",sizeof(a[0][0]));

        数组第一个元素,类型为int,计算得到4。

printf("%d\n",sizeof(a[0]));

        首先,我们在《指针进阶》博文中讲过,高维数组如n维数组,实际上是以n-1维数组维元素的一维数组,比如二维数组其实就是一维数组为元素的一维数组,这里的a[0]实际上就是一个一维数组数组名。

        如图,逻辑上分行分列模拟二维数组(实际存储时不是这样的)

         a[0]就是第一行数组的数组名,单独放在sizeof中,代表第一行数组,计算得到16。

printf("%d\n",sizeof(a[0]+1));

        这里a[0]代表第一行数组首元素地址,也就是&a[0][0],加个1就是向后偏移一位,也就是&a[0][1],是指针,计算得到4或8。

printf("%d\n",sizeof(*(a[0]+1)));

        就相当于*(&a[0][1]),即a[0][1],计算得到4。

printf("%d\n",sizeof(a+1));

        a这里代表首元素地址,也就是数组&a[0],再加个1就是&a[1],是指针,计算得到4或8。

printf("%d\n",sizeof(*(a+1)));

        相当于*&a[1]也就是a[1],是第二行数组数组名,单独出现在sizeof中代表整个数组,计算得到16。

printf("%d\n",sizeof(&a[0]+1));

        取出的是第一行数组的地址,再加1就相当于&a[1],是指针,计算得到4或8。

printf("%d\n",sizeof(*(&a[0]+1)));

        相当于*&a[1]即a[1],是第二行数组数组名,单独出现在sizeof中代表整个数组,计算得到16。

printf("%d\n",sizeof(*a));

        a代表&a[0],*a就相当于*&a[0],也就是a[0],是第1行数组数组名,单独出现在sizeof中代表整个数组,计算得到16。

printf("%d\n",sizeof(a[3]));

        看起来a[3]不是越界访问了吗,是不是会报警告呀?

        还记得前面梳理过的sizeof和strlen区别吗?

        sizeof只关注对应类型的变量占用内存空间的大小,而不在乎内存中放的是啥,并且在sizeof内并不会真的去访问a[3]。你看嘛,a[3]是不是相当于*(a+3),这是指针偏移后再解引用访问,a代表首元素地址也就对应的是int(*)[4]类型,a+3就是向高地址移动跳过三个int[4],而我们创建的二维数组也就只有三个int[4],这一跳就跳到了它后面,本来它后面的空间并没有分配给我们,我们是不应该也是不能访问的,可是架不住指针的权限大呀,间接访问还不行吗,越界是越界,但是通过指针是可以访问的。

        不过呢,可以访问但是sizeof并不会去访问,而是根据a[3]对应的类型计算这样类型的变量要占多大内存空间,a[3]相当于“第四行”数组的数组名,虽然不存在,可以假设其存在,因此计算得到16。

🍧指针笔试题

 

 

🍧第一题

🍧题目 

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}

🍧讲解

        &a取出整个数组地址,对应指针类型为int(*)[5],加个1跳过数组a指向数组后面一位,强转成int*后赋给了ptr,ptr-1就是向低地址方向移动一个单位,此时单位为4字节,正好跳过一个int型变量。a代表首元素地址,加个1就是第二个元素的地址,指向第二个元素。打印结果为2,5。

        如图所示:

 

🍧第二题

🍧题目

struct Test
{
     int Num;
     char *pcName;
     short sDate;
     char cha[2];
     short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,当下系统为x86(32位),结构体Test类型的变量大小是20个字节
int main()
{
     printf("%p\n", p + 0x1);
     printf("%p\n", (unsigned long)p + 0x1);
     printf("%p\n", (unsigned int*)p + 0x1);
     return 0;
}

🍧讲解

        0x1其实就是1,回顾一下前面讲的指针+-整数运算,步长与数据类型有关,如果类型为结构体指针struct Test*,其步长就为20,如果类型为unsigned int*,其步长就为4,所以第一个和第三个的打印结果就显而易见了:0x100014,0x100004。注意啦,第二个是强转成unsigned long类型,是整数类型,单位变成1了,所以结果就为0x100001。

🍧第三题

🍧题目

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);
    int *ptr2 = (int *)((int)a + 1);
    printf( "%x,%x", ptr1[-1], *ptr2);
    return 0;
}

🍧讲解

        &a取出整个数组地址,加个1跳到后面一位去了,再强转成int*赋给了ptr1,ptr1[-1]实际上就是*(ptr1-1),也就是向前跳了一个int变量后解引用,就得到4,打印是以十六进制显示,所以是0x00000004。

        a代表数组首元素地址,类型为int*,但是它被强转成了int型,此时+1的单位就是1,也就是只向后移动了一个字节,那我们一个字节一个字节来看,首先我们使用的机器用的是小端存储,倒着存倒着取,如图所示,看图就很清晰啦,得到的就是0x02000000。

小端存储不清楚的可以去这篇博文了解一下:点这里进去后看大小端字符序讲解

 

🍧第四题

🍧题目

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
 return 0;
}

🍧讲解

        这题有个小坑,要注意数组初始化时里面用的不是{ }而是( ),里面就是逗号表达式,表达式的值就是最后一个子表达式的值,所以初始化只按顺序放入了1,3,5。a[0]作为第一行数组数组名,代表首元素地址即&a[0][0],p[0]相当于*(p+0),也就是*p,即*&a[0][0],最后就是a[0][0]值为1。

🍧第五题

🍧题目

int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    return 0;
}

🍧讲解

        a是二维数组数组名,代表首元素地址也就是a[0]的地址,指针类型为int(*)[5],用p去接收a其实类型不兼容,但是可以把值放到p去,只是要访问时会有所差异。

        如图所示,指针相减得到间隔元素数量,小减大得负数,所以是-4,只是要注意打印用的转换说明不同,%p打印十六进制地址而%d打印十进制整数,-4对应补码为11111111111111111111111111111100,对应十六进制为0xfffffffc,而且地址没有原反补码之说,直接取出值打印即可。打印结果就是0xfffffffc,-4。

 

🍧第六题

🍧题目

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *ptr1 = (int *)(&aa + 1);
    int *ptr2 = (int *)(*(aa + 1));
    printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    return 0;
}

🍧讲解

        &aa取到整个数组地址,加个1就跳到数组后面一位,强转成int*后赋值给ptr1,ptr1-1就向前跳过一个int变量,解引用就得到10。

        aa代表二维数组首元素地址,也就是&aa[0],加个1向后就跳过一个int[5]数组,即&aa[1],解引用就是aa[1],代表其首元素地址即&aa[1][0],强不强转都是int*类型,赋给了ptr2,ptr2-1就向前跳过了一个int变量,再解引用就得到5。

 

🍧第七题

🍧题目

int main()
{
     char *a[] = {"work","at","alibaba"};
     char**pa = a;
     pa++;
     printf("%s\n", *pa);
     return 0;
}

🍧讲解

        这种题画图很重要,先把图画出来,剩下的就很容易观察分析了。

        解引用后是指向字符串"at"的指针,用%s作为转换说明来打印就得到"at"。

🍧第八题

🍧题目

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);
     return 0;
}

🍧讲解 

先画一画大体的图:

        看第一个, ++cpp就是&cp[1],解引用一次得到cp[1],再解引用*cp[1]即*(c+2)即c[2],按%s一打印得到"POINT"。

         

        看第二个,一步一步来,先是*++cpp即cp[2]即c+1,再--让cp[2]变成了c,解引用得到c[0],指向对应字符串首字符,再+3向后移动三位,再打印字符串就打印剩下的字符了,得到"ER"。

         看第三个,cpp[-2]即*(cpp-2)即c+3,再解引用得到c[3],指向对应字符串首字符,再+3向后移动三位,再打印字符串就打印剩下的字符了,得到"ST"。

         看第四个,cpp[-1][-1]即*(*(cpp-1)-1)得到c[1],指向对应字符串首字符,再+1向后移动一位,再打印字符串就打印剩下的字符了,得到"EW"。

         

        说实话这第八题我觉得是这里出现的最难的题了,能把这样的题给弄透彻的话,其实指针和数组这一块基本上就没什么大问题了。

 

 


🍧敬请期待更好的作品吧~

感谢观看,你的支持就是对我最大的鼓励,阁下何不成人之美,关注点赞收藏走一波~

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桦秋静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值