1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 指针相关题目详解(看完写完后保证能把指针相关问题理清)

指针相关题目详解(看完写完后保证能把指针相关问题理清)

时间:2018-10-12 13:34:49

相关推荐

指针相关题目详解(看完写完后保证能把指针相关问题理清)

不多说了,干货满满,下面是本人保肝12个小时整理出来的题目以及题解图解。保证质量。

指针题目

Tips:

当数组名没有出现在sizeof内部的时候,数组名代表的就是首元素的地址。

而在sizeof内部只有数组名时,输出的结果就是所以元素的总和大小

请计算下面输出结果:

#include <stdio.h>int main(){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));return 0;}

我们来一条一条的仔细分析

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

这里是sizeof括号内只有数组名,所以要打印出来的是一整个数组的大小,即为16

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

sizeof括号内不知数组名了,所以这里不指整个数组,此时的数组名指的是数组首元素的地址,而首元素地址+0还是为首元素地址,所以最后输出的结果为4或8

Tips:地址在32位上的内存大小为4哥字节,在64位上是8个字节。

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

sizeof括号内为a,已知a是数组首元素地址,所以*a为数组的首元素,int型,占四个字节,所以打印结果为4.

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

a是首元素地址,+1后为第二个元素的地址,都为地址,所以最终输出结果为4或8

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

a[1]指的是2,为int型,所以最终打印出四个字节

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

&为取值符,在这里取的是整个数组的地址,所以最终打印出4或8

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

*&相互抵消后,只剩下a了,所以相当于sizeof(a),所以最终打印出16

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

我们已经知道&数组名代表的是整个数组的地址,所以&a+1指的是跳过整个数组指向数组最后一个元素地址的下一个位置。为地址,所以最后打印出4或8。图解如下(因为感觉本人不太会描述):

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

这是取到的数组首元素地址,所以最终打印出4或8。

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

&a[0]+1也就是第二个元素的地址,所以最终打印出4或8

计算出下面结果:

#include <stdio.h>int main(){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));return 0;}

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

当sizeof内放入的是数组名时,输出的是整个数组的大小,单位是字节,所以大小是6个字节.

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

arr+0指的是数组首元素地址,所以大小是4或8个字节

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

*arr指的是第一个元素,为char型,所以大小是1个字节。

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

这里指的是数组中的第二个元素,是一个字符,所以大小是1个字节。

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

&arr是指整个数组的地址,大小是4或8个字节。

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

&arr+1指的是从数组首元素位置,往后跳过一整个数组大小的位置的地址,地址大小就是4或8个字节

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

&arr[0]+1指第二个元素的地址,地址大小是4或8个字节

计算下面结果:

#include <stdio.h>int main(){char arr[] = { 'a','b','c','d','e','f' };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));return 0;}

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

arr指的是是首元素地址,代表从第一个元素的地方开始向后计算长度,但由于没有'\0',所以不知道会计算到多长,输出结果为随机值。

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

arr是首元素地址,arr+0还为首元素地址,所以输出结果为随机值。

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

error,strlen需要的是一个地址,从这个地址开始向后找字符,知道\0,统计字符的个数。但是*arr是数组的首元素,也就是'a',这时传给strlen的就是'a'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突。

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

和上面同样道路,error,原因是内存访问冲突。

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

虽然&arr指的是整个数组的地址,虽然和strlen的参数类型有差异,但都是从首元素开始,传进去的是首元素地址,所以最后输出结果是随机值。

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

同上差不多,但是是从首元素地址开始往后跳过一整个数组大小的位置的地址开始向后读取的,输出结果也是随机值。

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

&arr[0]+1指的是第二个元素地址,即从第二个元素往后读取长度,但由于没有'\0',所以不知道会计算到多长,输出结果为随机值。

计算下面结果:

#include <stdio.h>int main(){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));return 0;}

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

sizeof内部放入单独数组名,指的是放入整个数组,arr数组虽然赋值时为“abcdef”,但其实还有一个隐藏的“\0”,所以整个数组大小为7个字节。

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

arr+0指的是第一个元素的地址,大致的大小为4或8个字节。

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

*arr指的是第一个元素,为char类型,大小为1个字节。

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

arr[1]指数组第二个元素,为char类型,大小为1个字节。

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

&arr为整个数组的地址,地址大小为4或8个字节。

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

&arr为整个数组的地址,&arr+1指从首元素地址处开始往后跳一个数组大小的位置的地址,而地址大小为4或8个字节。

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

&arr[0]+1指的是数组的第二个元素的地址,地址大小为4或8个字节。

计算下面结果:

#include <stdio.h>int main(){char arr[] = "abcdef";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));return 0;}

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

由于arr初始化是是用的“abcdef”的方式,所以f后还有一个隐藏的“\0”,所以当从首元素地址向后读取,最终输出结果为6。

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

arr为首元素地址,+0后还是首元素地址,所以将首元素地址传给strlen函数,最终输出结果为6。

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

error,arr指的是首元素地址,*arr指的是'a',a的ascii码值为97,strlen函数会把97作为起始地址,向后统计字符串,会形成内存访问冲突。

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

arr[1]指的是数组第二个元素,即'b',同上,会error,原因是会形成内存访问冲突。

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

虽然&arr指的是整个数组的地址,但也是从首元素地址开始的,所以尽管与strlen传入参数类型不符,也能够从首元素地址开始向后统计字符串直至遇到'\0',所以最终输出结果为6。

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

&arr+1指从首元素地址处开始往后跳一个数组大小的位置的地址,即从此位置的地址传入给strlen函数,往后读取,但由于不知道在什么位置才能碰到'\0',所以最终输出结果为随机值。

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

&arr[0]+1即为第二个元素的地址,将第二个元素地址传入strlen函数,最终结果为5。

计算下面结果:

#include <stdio.h>int main(){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));return 0;}

Tips:在这里,p作为char*指针变量,存放的是首元素a的地址。

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

因为p为char*指针变量,指针变量大小为4或8个字节。

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

由于p是char*指针,指向的是字符串中的a的地址,所以p+1是指字符串中的'b'的地址,地址的大小为4或8个字节。

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

p内存放的是a的地址,*p后得到的是a,a为char型变量,大小为1个字节。

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

p[0]==*(p+0),所以在这里指的是首元素a,a为char型变量,大小为1个字节。

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

&p代表的是p指针的地址,地址的大小为4或8。

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

&p+1还是地址,是跳过p变量后的地址,地址大小为4或8个字节。

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

&p[0]指的是a元素的地址,+1后指的是第二个元素‘b’的地址,地址大小为4或8个字节。

计算下面结果:

#include <stdio.h>int main(){char* p = "abcedf";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));return 0;}

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

用的“abcdef”的方式,所以f后还有一个隐藏的“\0”。这里的p存的是'a'的地址,传入给strlen函数后读到'\0'便停止了,所以最终结果为6。

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

由于p指针存的是'a'的地址,+1后存的是'b'的地址,所以将b的地址传入给strlen函数向后读取,最终结果为5。

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

error,由于p指针存的是'a'的地址,所以*p得到的就是a,而a的ascii码值为97,将97作为起始地址传入给strlen函数,向后读取字符串,会造成内存访问冲突。

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

p[0]==*(p+0)==*p,所以p[0]得到的是a,而此情况同上,会报错error,造成内存访问冲突。

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

&p取到的是指针变量p的地址,把p指针的地址作为起始地址传入给strlen函数向后读取,但由于不知道什么时候能碰到'\0',所以最终输出结果为随机值。

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

&p取到的是指针变量p的地址,+1后取到的是p变量后面的地址,同样作为起始地址传入strlen函数后,我们并不知道什么时候会碰到'\0'停止,所以最终输出结果为随机值。

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

p[0]指的是字符串中的'a',&p[0]+1即为取到a的地址后+1,即为b的地址,将b的地址作为起始地址传入给strlen函数向后读取,所以最终输出结果为5。

计算下面结果:

#include <stdio.h>int main(){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]));return 0;}

Tips:在二维数组中,数组名表示首元素地址,*数组名就是二维数组的首元素,也就是第一行。也可以这么看:a—>(a+0)—>a[0]→第一行数组名。

a[0]相当于是第一行的数组名,同样也符合当数组名单独放在sizeof内部时表示会计算整体大小。

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

在sizeof内部只有数组名,所以是按照整个数组的大小来进行计算的,大小为3*4*4=48个字节。

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

a[0][0]为数组首元素,int型,大小为4个字节。

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

a[0]是第一行的数组名,单独放在sizeof内部是会算整体大小,就是这一行的大小,为16个字节。

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

a[0]是第一行的数组名,+1后会跳过一整行,变为第二行的数组名,将数组名单独放入sizeof函数内部,算整行大小,为16个字节。

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

a[0]为第一行的数组名,加一后变为第二行的数组名,解引用后指向当行的第一个元素,为int型,大小为4个字节。

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

a不是单独的放在sizeof内部,a是数组首元素,也就是第一行的地址,+1后变为第二行的地址,是类型为int(*)[4]的数组指针,地址就是4或8个字节。

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

上题可知a+1为第二行地址,解引用后就得到了第二行的数组名,数组名单独放在sizeof内部,表示整个第二行的大小,为16个字节。

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

因为&a[0]—>*(a+0)—>*a,所以&a[0]相当于&*(a),&和 * 相当于抵消掉了,剩下a+1,情况与上上题相同,int(*)[4]类型的数组指针,大小为4或8个字节。

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

a[0]—>a,又因为前面有一个&,与抵消后得到的是数组的首元素a,也就是第一行的地址,+1后变为第二行地址,然后再解引用,得到的便是第二行的数组名,数组名单独放在sizeof内部,得到的是整体的大小,第二行整体大小为16个字节。

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

a是数组首元素,也就是第一行的地址,解引用后得到的是数组第一行的数组名。直接将数组名放入sizeof函数内,得到整行的大小,为16个字节。

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

虽然感觉a[3]越界了,但是没关系,其实sizeof并不会真正去访问,只是会通过变量来推导类型,所以并不会真的去访问它。在这里a[3]其实是数组指针类型,int (*)[3],大小为4或8个字节。

总结:

数组名的意义:

sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。&数组名,这里的数组名表示整个数组,去除的是整个数组的地址。除此之外所有的数组名都表示首元素的地址。

计算下面结果:

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

直接图解:

所以最终输出结果为2,5

计算下面结果:

#include <stdio.h>struct Test{int Num;char* pcName;short sDate;char cha[2];short sBa[4];}*p;//假设p的值为0x100000。如下表达式的值分别为多少?//已知,结构体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;}

printf("%p\n", p + 0x1);

p是结构体指针(struct Test*),对指针+1,就相当于加上指针对应类型所占的内存大小,在这里我们可以知道Test类型的变量大小为20个字节,所以最终结果为0x100000+0x000014=0x100014。

printf("%p\n", (unsigned long)p + 0x1);

因为这里我们强制类型转换成了unsigned long型,所以0x100000是实实在在的数字,加一就是加一了,所以最终结果为0x100000+0x000001=0x100001

printf("%p\n", (unsigned int*)p + 0x1);

在这里因为强制类型转换成unsigned int*指针类型,对指针类型加一,相当于加上指针对应类型所占的空间大小,int的大小为4个字节,所以0x100000+0x000004=0x100004。

Tips:%p以地址的形式打印,有效数字前的0不省略

%x就是打印16进制,省略有效数字前的0

计算下面结果:

#include <stdio.h>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;}

int* ptr1 = (*int)(&a + 1);

已知&a是整个数组的地址,+1后跳过整个数组指向整个数组的后一个元素,又因为ptr为int*型指针,ptr1[-1]我们可以看作是(ptr1-1),也就是指向了上一个元素。(算了还是直接图解吧....)

下面是图解:

所以最终ptr1[-1]的输出结果为4

int* ptr2 = (int*)((int)a + 1);

a是数组名,储存首元素地址,强制类型转换为int型后+1相当于地址加1(因为不是指针类型了所以无法加上4个字节),之后又转换成指针类型,以加一后的地址形式解引用出来,下面是图解:

而我们读取到的内存里的内容,会因为编译器的大小端字节序的不同而产生不同结果

(若有不了解大小端字节序的人可以点击这里,博主在前面的博客中有介绍到),用小端字节序为例,如图:

端字节序大家可以试着自己推算一下,最终结果为65,536(十进制)。

计算下面结果:

#include <stdio.h>int main(){int a[3][2] = { (0,1),(2,3),(4,5) };int* p;p = a[0];printf("%d", p[0]);//*(a[0])return 0;}

最终的输出结果为1喔。

int a[3][2] = { (0,1),(2,3),(4,5) };注意在这段代码中是(0,1)(2,3)(4,5)而非{0,1}{2,3}{4,5},而(0,1)(2,3)(4,5)最后会得到1,3,5。

(这里相关逗号操作符,不懂得为何会取得1,3,5可以点击这里查看本人写的另一篇博客)。

所以a[3][2]={1,3,5,0,0,0,};

p = a[0];

在经过之前的魔鬼式训练后,都知道a[0]是数组名,表示首元素地址,指向第一个元素,储存在p内而p[0]相当于*p,所以最终输出1。

计算下面结果:

#include <stdio.h>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;}

int a[4][2]想必大家都是能清楚的,由于都为指针类型,指针与指针类型相减得出的是两个指针之间的元素个数,又因为是小地址减大地址,所以%d对应的打印结果为-4。

int型都是以补码的形式进行存储,%p是直接将补码给打印出来的。-4的补码为ff ff ff fc。

所以最终的打印结果为ff ff ff fc, -4。

计算下面结果:

#include <stdio.h>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;}

这个与前面有一道题类似,这里就不作过多解释了,自己推算一下吧~

最终输出结果为:10,5

计算下面结果:

#include <stdio.h>int main(){char* a[] = { "Work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;}

char* a[] = { "Work","at","alibaba" };

上面为指针数组类型,每一个元素的类型都为char*类型,一共有三个元素,第一个char*→"Work\0",第二个char*→"at\0",第三个char*→"alibaba\0"。

char**pa = a;

此时将数组名赋给二级指针pa,相当于pa取得了指针数组的首元素,当pa++时,会跳过的指针对应类型的大小,所以来到了第二个char的位置,解引用后得到的是第二个char对应的“at\0”。

所以最终的输出结果为at。

计算下面结果:

#include <stdio.h>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,c的图解。

printf("%s\n",**++cpp);

我们可以知道cpp是cp的指针,指向cp的地址,所以cpp会指向cp,而cp又指向c,所以cp会得到c的地址。

由图,++cpp指向的是c+2处,而c+2指向在图中圈起的char*。其保存着"POINT\0",所以这行最后的打印结果为POINT。

printf("%s\n",*-- * ++cpp +3);

在原本的cpp位置上再+1得到图中指向的位置,该位置存储了c+1,解引用cpp后就得到了指针指向的c+1,再 - -,得到c,c指向的是存储“ENTER\0”的char*,所以解引用后得到的是第一个E的位置,再+3后指向的是第二个E的位置。所以最后从第二个E开始打印,最终的打印结果为ER。

printf("%s\n", *cpp[-2]+3);

cpp[-2]等同于*(cpp-2),但由于此行代码为“cpp-2”,只是变成了图中橙色指向cp的箭头,而cpp本身没变,如果是“++cpp”或者是“cpp++”,才是cpp本身指向地址改变。所以此时cpp还是指向图中的绿色箭头位置。而代码中的*(cpp-2)指向c+3的位置,再次解引用,我们会得到指向“FIRST\0"的指针char*,解引用后指向F,+3后指针指向了S。所以最终从S开始打印,最终的打印结果为ST。

printf("%s\n", cpp[-1][-1]+1);

cpp[-1][-1]我们可以看作是*(*(cpp-1)-1),先从*(cpp-1)开始看起,cpp-1指向的是c+2的位置,解引用后指向了指向"POINT\0"的指针char*,(*(cpp-1)-1)得到图中粉色箭头位置,变为了指向“NEW\0”的首元素“N”的指针,+1后指向“E”,所以最终打印结果为EW。

以上,便是全部题目了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。