70道指针数组笔试题

Posted 梦乡回雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了70道指针数组笔试题相关的知识,希望对你有一定的参考价值。

本文指针数组笔试题可以用来检测你对指针的掌握程度ヽ( ̄▽ ̄)ノ大家自己看看自己对指针掌握怎么样吧!

温馨提示:建议大家先看目录中的题先自行思考一下,再去点击对照(默认32位条件)


文章目录


一、数组笔试题

1、一维数组 int a[] = {1,2,3,4};

  • 答案:

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

  • sizeof(数组名),求的是整个数组的大小(单位是字节) 4 × 4 = 16

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

  • 这里注意a表示的是数组首元素的地址,a+0,a并没有变化,a就是地址,也就是求首元素地址(整型指针大小)也就是 4 (字节)(64位 8 字节)

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

  • 这里* a就相当于 - *(a+0),也就是a [ 0 ] ,int 型,大小4 (字节)

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

  • 这里a表示首元素地址,a+1表示a [ 1 ]的地址,求一个地址大小:4 (字节)(64位 8 字节)

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

  • a[1],整型元素:4 (字节)

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

  • &数组名,这里数组名表示整个数组首地址,但是还是地址 :4 (字节)

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

  • &数组名,这里数组名 a 表示整个数组首地址,再解引用得到的是 a。 也就是sizeof(a)求整个数组大小 :16(字节)

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

  • &a,a表示的是整个数组首地址,+1表示加另一个数组,加到数组后边,但是还是求地址大小:4(字节)(64位 8 字节)

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

  • 整型元素地址大小:4(字节)(64位 8 字节)

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

  • +1并没有影响,整型元素地址大小:4(字节)(64位 8 字节)

2、字符数组一:char arr[] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’};

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

  • sizeof(数组名),求的是整个数组的大小(单位是字节) 6 × 1 = 6

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

  • arr这里表示首元素的地址,arr+0,不变,求地址大小:4(字节)(64位 8 字节)

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

  • arr这里表示首元素的地址,*arr表示 首 元 素 arr[0],char类型大小1字节

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

  • char类型大小1字节

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

  • &arr,arr表示整个数组首地址,求地址大小:4(字节)(64位 8 字节)

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

  • +1调到数组后边,本质还是地址,大小还是:4(字节)(64位 8 字节)

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

  • 求地址大小:4(字节)(64位 8 字节)

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

  • 这里注意声明的时候arr数组只有6个元素并没有\\0结束标志,所以当会从arr开始一直往后找知道遇见 ’ \\0 ‘ 才会停止,所以是个随机值。

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

  • 这里arr表示数组首元素的地址,所以还是同上随机值

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

  • 这里arr表示数组首元素的地址,* arr 表示 取到首元素 a . 也就是对应ASC码表里的97传递给strlen( ) 函数,strlen函数会从97对应的地址处开始查找,所以会报错!!!

  • 这里十六进制61也就是16 * 6 + 1 = 97

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

  • 这里arr【1】,表示把 b 也就是 98传给strlen函数,所以还是同上err

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

  • 这里arr表示数组首地址,前边加上 & 还是表示地址,所以还是对应的随机值

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

  • 这里arr表示数组首地址,+1,跳过整个数组,从数组后开始往后寻找\\0,所以是随机值 -6

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

  • 这里 &arr【0】表示首元素地址,+1,只是跳过数组的一个元素,从b开始往后寻找\\0,所以是随机值 -1

3、字符数组二:char arr[] = “abcdef”;

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

  • sizeof(数组名)表示求数组大小,这里数组有七个元素,大小7*1 = 7

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

  • 这里arr 表示数组首元素地址 , +0,不变,也就是求地址大小:4(字节)(64位 8 字节)

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

  • 这里arr 表示数组首元素地址 , *arr取到首元素a[0],结果是:1

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

  • 这里 arr[1],char类型结果是:1

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

  • 这里 &arr表示整个数组首地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里 arr表示整个数组首地址,+1,跳过整个数组,但还是地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里 &arr【0】表示首元素地址,+1,也就是arr[1]的地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里 注意 strlen遇到\\0停止,不算\\0,所以结果是6

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

  • 这里 arr表示数组首元素地址,+0,不变。还是6

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

  • 这里 arr表示数组首元素地址,*arr取到数组首元素a,相当于把对应的97当做地址传过去,报错

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

  • 同上,报错

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

  • 这里 arr表示数组首地址,&arr,还是6

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

  • 这里 arr表示数组首地址,&arr+1,跳过整个数组。在\\0之后开始寻找\\0,随机值

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

  • 这里&arr【0】+1,也就是arr[1]地址,从b开始往后找\\0。是5

4、字符数组三:char *p = “abcdef”;


※注意这里char *p = “abcdef”;的意思是把整个字符串的首地址(也是a的地址)放入到字符型指针 p里

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

  • sizeof( p),这里p只是一个指针变量并不是数组名,所以是求地址大小:4(字节)(64位 8 字节)

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

  • 这里p指向的是字符串首地址,也就是 a 的地址,p+1,也就是b 的地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里&p指向的是字符串首地址,也就是 a 的地址,*p也就是a,字符型,大小是1

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

  • p【0】相当于*( p + 0 ),也就是a,字符型,大小是1

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

  • 这里&p,也就是字符变量p地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里&p,也就是字符变量p地址,+1越过p。还是个地址,求地址大小:4(字节)(64位 8 字节)

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

  • 这里&p【0】+1,也就是 a 的地址+1,b的地址。求地址大小:4(字节)(64位 8 字节)

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

  • 这里p表示字符串首地址也就是 a 的地址,从a开始往后数直到| \\ 0 。结果是6

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

  • 这里p+1,从a越过一个元素到b开始往后数直到| \\ 0 。结果是6-1 = 5

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

  • 这里p表示字符串首地址也就是 a 的地址,*p表示a,也就是把97传给strlen,报错

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

  • 同上,报错

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

  • 这里&p表示p的地址,从p开始往后数直到| \\ 0 。结果是随机值

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

  • 同上也是随机值,但是注意!!!这个随机值你无法保证是上一个随机值 – 4 (4是p指针类型的大小),因为你无法保证p的内容4个字节中是否会有\\0!!!!

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

  • 这里p【0】,*( p + 0 ) 也就是a,+1也就是调到b。从b开始往后数直到| \\ 0 。结果是6-1 = 5

5、二维数组:int a[3][4] = {0};

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

  • sizeof(数组名),表示求整个数组大小,也就是12*4 = 48

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

  • a【0】【0】,int大小 4 (字节)

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

  • 这里a [ 0 ] 单独放在sizeof,可以理解为二维数组第一行
    sizeof(a【0】)就是求第一行的一维数组大小,也就是16

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

  • 这里a【0】,并没有单独放在sizeof内部,也没有取地址,所以a[0]表示的就是第一行第一个元素的地址也就是整个数组的首地址,+1跳过一个元素也就是第一行第二个元素的地址,也就是4 (字节)(64位 8 字节)
  • 那么实际上二维数组在内存中是连续存放的:::

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

  • 同上,对第一行第二个元素取地址并求大小,4

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

  • 这里二维数组数组名并没有单独放在sizeof里,所以表示的就是二维数组第一行的首地址,+1,越过的是一整行,变成第二行首地址,4(字节)(64位 8 字节)

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

  • 同上(a + 1)表示第二行首地址,解引用就是取得整个第二行,也就是16.
  • 并且*(a+1)等价于a【1】,也就是整个第二行大小16

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

  • 这里&a【0】取得整个第一行一维数组首地址,+1变成第二行地址。求地址大小:4(字节)(64位 8 字节)

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

  • 同上,对整个第二行一维数组首地址解引用,求得的是整个第二行,大小16

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

  • 这里二维数组数组名并没有单独放在sizeof里,这里a表示二维数组首元素地址,二维数组有三个部分,首元素就是第一行,也就是第一行地址。*a表示第一行的地址,大小16
  • 或者你也可以这么理解*a也可以写成 *( a + 0 ),也就是a【0】第一行大小16

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

  • 或许你会疑问a[3]明显越界访问了,但是你要注意!,sizeof()括号里的表达式是不做任何运算的!!!这个代码没有任何问题的!!!!!

  • a【3】其实是第四行的数组地址(实际上不存在),但是可以通过数组声明的类型大小推断出大小是16。(实际上并么有去访问,没有越界)

总结: 数组名的意义:

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

二、指针笔试题

笔试题1

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
  • &a + 1,首先&a,这里的是取得整个数组的首地址,+1跳过的是整个数组!!
  • *(a + 1),等价于a [ 1 ]。

笔试题2

代码如下(示例):

struct Test
{
 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
 printf("%p\\n", p + 0x1);
 printf("%p\\n", (unsigned long)p + 0x1);
 printf("%p\\n", (unsigned int*)p + 0x1);
 return 0; 
}//这里告知结构体的大小是20个字节
  • 假设p 的值为0x100000 , 那么注意p在这里的类型,p是Test结构体类型指针,指向的是大小是20,+1跳过的是Test大小也就是 20转换成十六进制也就是0x14.结果也就是0x100014
  • 这里把p先强转成无符号长整型。再加1也就是变成整型数据+1也就是0x100001
  • 这里把p先强转成无符号整型指针,本身类型大小是四字节。这里+1,也就是+4,答案是0x100004

笔试题3

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;
}
  • 答案:4 200000

  • ptr1 :&a + 1,首先&a,这里的是取得整个数组的首地址,+1跳过的是整个数组!!

  • ptr2 :(int)a + 1,这里注意a是数组名,表示的是数组首元素的地址,首先被转化成整型,但是注意此时+1跳过的是1(字节),再转化成地址,此刻就涉及到储存模式,我们以大多数编译器的小端存储模式来说明:

笔试题4

#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
 return 0; }
  • 答案:1
  • 这道题要注意一个坑 :逗号操作符
  • (0, 1)实际上是把1存进去跟0没有关系!!!!p 指向第一行,p[0]表示取得第一行第一个元素,也就是a[0][0]

笔试题5

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; 
}
  • 答案: FFFFFFFC -4

  • 首先看类型a是二维数组,p是(指向4个整型数据数组的)指针,数组名a表示二维数组首地址也就是第一行首地址,赋给p。(这里编译器会报错,因为大小p是指向4个Int的,二维数组a每行有5个元素,但是确实可以这么做的)

  • 如果以%d形式打印,直接打印出来-4.

  • 如果以%p形式打印,首先-4是需要以补码形式储存的
    10000000 00000000 0000000 00000100— 原码–4
    111111111 111111111 11111111 111111100— 补码–4
    FFFFFFFC–%p十六进制–4

笔试题6

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
  • (int *)(&aa + 1):&aa表示取得整个数组的首地址,那么+1跳过的是整个数组
  • (aa + 1):aa这里表示二维数组首元素的地址,而二维数组的首元素就是第一行,aa也就是第一行的地址,+1表示跳过一整行,就是第二行。*(aa + 1)等价于 aa[1]

笔试题7

	char* a[] = { (char*)"work",(char*)"at",(char*)"alibaba" };
	char** pa = a;
	pa++;
	printf("%s\\n", *pa);
  • 答案:at
  • 首先a的类型是指针数组,这里a是数组名,表示数组首元素的地址,数组首元素是个一级指针,一级指针的地址需要二级指针来存放,也就是pa存放的a(work字符串的首地址)。pa++,跳过一个元素,也就是at的首地址

笔试题8

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;
}
  • 答案:POINT ER ST EW

  • 对应关系如图:

  • printf("%s\\n", **++cpp); 首先++cpp,指向c+2,取地址 *,取到c+2,再取地址 *,取到POINT字符串

  • printf("%s\\n", * - - *++cpp +3); 注意操作符优先级!!首先++,(这里注意上个语句cpp已经++过了指向c+2),cpp指向c+1,取地址,取到c+1,- -,变成c,再取地址,得到ENTER字符串首地址,此时+3往后越过3个字符,从E地址开始打印结果ER。

  • printf("%s\\n", *cpp[-2]+3); cpp已经指向c+1,cpp[-2]相当于 *(p-2)得到c+3,c+3中存放的是FIRST字符串首地址,取地址得到也就是F的地址,+3,到S地址,打印结果ST

  • printf("%s\\n", cpp[-1][-1]+1); 第一个【-1】相当于*(p - 1),取得c+2,再来一次【-1】相当于*(c+2-1),也就是NEW首地址也就是N的地址,+1越过N,E的地址,打印出EW


如果小伙伴上边的题都能作对,那么我在这里衷心的喊一声666,说明你对指针的掌握已经很好很不错了!!


写在文尾:

等等,昨天的不开心就让他随昨天过去吧,今天的你要开心哦!!
-----------------------------------------------------------祝你:---------------------------------------------------

以上是关于70道指针数组笔试题的主要内容,如果未能解决你的问题,请参考以下文章

笔试题:递归快速排序复杂度等5选择题道题(顺丰2017校招研发)

指针进阶—指针和数组笔试题解析[建议收藏]

指针中容易混淆的概念以及常见笔试题

JavaScript笔试题(js高级代码片段)

指针进阶—指针和数组笔试题解析[建议收藏]

史上最强C语言教程----指针(笔试题1)