【C语言进阶】 指针和数组笔试题解析

目录

数组笔试题

一维数组

字符数组

题  一

题  二

题  三

题  四

题  五

题  六

二维数组  

指针笔试题

笔试题一

笔试题二 

笔试题三

笔试题四

笔试题五

笔试题六 

笔试题七 


 

本篇博文,将从指针和数组来为大家分析一些笔试题,设计内容多,全是干货,接下来让我们一起来看一下吧

数组笔试题

在做题之前,我们需要明白

数组名是数组首元素的地址
  但是有2个例外:
  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

一维数组

我们首先看题,答案再代码后面

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//  16
printf("%d\n",sizeof(a+0));//  4/8
printf("%d\n",sizeof(*a));//  4
printf("%d\n",sizeof(a+1));//  4/8
printf("%d\n",sizeof(a[1]));//  4
printf("%d\n",sizeof(&a));//  4/8
printf("%d\n",sizeof(*&a));//  16
printf("%d\n",sizeof(&a+1));//  4/8 
printf("%d\n",sizeof(&a[0]));//  4/8
printf("%d\n",sizeof(&a[0]+1));//  4/8

接下来博主会为大家一句一句进行解释

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

解释:sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,所以是16

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

解释:这里的sizeof没有和a直接相连,所以这里并不是整个数组,这里a代表数组首元素的地址,a+0依然是首元素的地址,既然是地址,所以大小为4或8,具体大小由编译器决定

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

解释:*a是数组的首元素,且为int型,所以大小为4

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

解释:a为首元素的地址,a+1为第二个元素的地址,所以大小为4或8

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

解释:a[1]为第二个元素,大小为8

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

解释:&a为地址,所以大小为4或8

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

解释:&a是a的地址,前面加上解引用*,则*&a就为a,所以大小为16

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

解释:&a是地址,那么&a+1也还是地址,所以大小为4或8

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

解释:&a[0]是首元素地址,既然是地址,所以大小为4或8

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

解释:&a[0]为地址,那么&a[0]+1也是地址,既然是地址,所以大小为4或8

字符数组

题  一

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//  6
printf("%d\n", sizeof(arr+0));//  4/8
printf("%d\n", sizeof(*arr));//  1
printf("%d\n", sizeof(arr[1]));//  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

解释如下

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

解释:数组名单独放在sizeof内部,这里的arr表示整个数组,计算的是整个数组的大小,单位是字节,总共6个字节

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

解释:arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节

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

解释:arr表示数组首元素的地址,*arr就是首元素,大小1个字节

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

解释: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));

解释:第二个元素的地址,是4/8个字节

题  二

char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机值
printf("%d\n", strlen(arr + 0));//arr 
printf("%d\n", strlen(*arr));//err
printf("%d\n", strlen(arr[1]));//err
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值

在讲解提二是我们需要了解以下strlen这个函数

608c1650ba71438182c081a6549ae913.png

 格式为

fb97b737203f448f9169c5244708d55b.png

还需要了解一下这个arr的存储

b95cd84b65234d3ea0ae9084e760a958.png

 

明白这些后,我们开始解释代码

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

解释:因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值

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

解释:arr + 0是首元素的地址,和第一个一样,也是随机值

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

解释: arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97,strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参,strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了,如果访问就会出现下面的情况

1dc18cea71b74da8b75b208e23ca68d8.jpeg

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

 解释:与上一条同理

printf("%d\n", strlen(&arr));//随机值

解释:&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计直到/0结束

printf("%d\n", strlen(&arr + 1));//随机值

解释:与&arr类似,&arr+1是数组的地址加一,所以也是随机值

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

解释:&arr[0] + 1是第二个元素的地址。结果也是随机值

题  三

char arr[] = "abcdef";//[a b c d e f \0]
printf("%d\n", sizeof(arr));//7
printf("%d\n", sizeof(arr + 0));//4/8
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//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

我们先看一下arr里面都有什么吧

d461608cd09043fb97989904f7d21c55.png

解释如下

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

解释:arr中存储了7个char型色元素,所以为7

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

解释:arr + 0是首元素的地址,是地址,所以为4/8

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

解释:*arr其实就是首元素,1个字节。等价关系:*arr--> *(arr+0) -- arr[0]

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

解释:arr[1]是第二个元素,1个字节

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

解释:&arr是数组的地址,是地址就是4/8个字节

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

解释:&arr + 1是跳过一个数组的地址,是地址,所以为4/8

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

解释:&arr[0] + 1是第二个元素的地址,是地址,所以4/8

题  四

//	char arr[] = "abcdef";//[a b c d e f \0]
//	printf("%d\n", strlen(arr));//6
//	printf("%d\n", strlen(arr + 0));//6
//	printf("%d\n", strlen(*arr));//*arr为首元素,所以这里错误,err
//	printf("%d\n", strlen(arr[1]));//arr[1]为第二个元素,所以这里也错误
//	printf("%d\n", strlen(&arr));//6
//	printf("%d\n", strlen(&arr + 1));//随机值
//	printf("%d\n", strlen(&arr[0] + 1));//5

这题我就不一一解释了,各位宝子们结合下图与前面所讲.看懂本题是没有问题的

a56db019e8674f5ca05b967a00c2c270.png

题  五

char *p = "abcdef";
printf("%d\n", sizeof(p));//  4/8
printf("%d\n", sizeof(p + 1));//  4/8
printf("%d\n", sizeof(*p));//  1
printf("%d\n", sizeof(p[0]));// 1个
printf("%d\n", sizeof(&p));// 4/8
printf("%d\n", sizeof(&p + 1));// 4/8
printf("%d\n", sizeof(&p[0] + 1));//  4/8

解释如下

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

解释:p是一个指针变量,指针大小为4/8

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

解释:p+1是'b'的地址,是地址大小就是4/8个字节

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

解释:*p 就是'a',就是1个字节

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

解释:p[0]等价 *(p+0)等 价 *p ,所以1个字节

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

解释:都为地址,所以大小都为4/8个字节

题  六

//	char* p = "abcdef";
//	printf("%d\n", strlen(p));//6
//	printf("%d\n", strlen(p + 1));//5
//	//printf("%d\n", strlen(*p));//err
//	//printf("%d\n", strlen(p[0]));//err
//	printf("%d\n", strlen(&p));//随机值
//	printf("%d\n", strlen(&p + 1));//随机值
//	printf("%d\n", strlen(&p[0] + 1));//5

这题我就不详细讲解了,请各位宝子们配合下图与前面所讲自行理解一下吧

86b40a0011284d749e404615ee34f004.png

二维数组  

int a[3][4] = {0};
printf("%d\n",sizeof(a));// 48
printf("%d\n",sizeof(a[0][0]));// 4
printf("%d\n",sizeof(a[0])); // 16
printf("%d\n",sizeof(a[0]+1));// 4/8
printf("%d\n",sizeof(*(a[0]+1)));// 4
printf("%d\n",sizeof(a+1));// 4/8
printf("%d\n",sizeof(*(a+1)));// 16
printf("%d\n",sizeof(&a[0]+1));// 4/8
printf("%d\n",sizeof(*(&a[0]+1)));// 16
printf("%d\n",sizeof(*a));// 16
printf("%d\n",sizeof(a[3]));// 16

在做题之前,务必知道下图中的知识点

41e7a36b2cc5473aa037d0997131ced8.png

二维数组可以看成存放着一维数组的数组 ,接下来我们看一下题解

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

解释:3*4*4 = 48

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

解释:首元素a[0][0]的大小

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

解释:a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节

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

解释:a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&。a[0]表示数组首元素的地址,也就是a[0][0]的地址。所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节

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

解释:计算的是就是第一行第2个元素的大小

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

解释:a是数组首元素的地址,是第一行的地址 int(*)[4]。a+1 就是第二行的地址 

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

解释:*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小。a+1 --> 是第二行的地址,int(*)[4]。*(a+1) 访问的第二行的数组

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

解释:&a[0]是第一行的地址 int(*)[4],&a[0]+1 是第二行的地址 int(*)[4] 

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

解释:计算的是第二行的大小

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

解释:计算的是第一行的大小-16。a是数组首元素的地址,就是第一行的地址。*a 就是第一行,*a 等价于*(a+0) 等价于 a[0]

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

解释:a[3]等价于int [4],所以大小为16

指针笔试题

笔试题一

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

解释图如下

830e4fd054144319bacba8d33984f5f6.png

笔试题二 

//这里告知结构体的大小是20个字节
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;
}

这里我们注意我们如果要运行这个代码,并得出题中所要求的结果,我们还需要对*p进行改造,如下

//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}* p = (struct Test*)0x100000;

这样p就等于0x100000,就可以开始运行测试了,运行结果如下

5f92130e76be4f63bc42de9be350c70a.jpeg  

这道题我们来一句一句解读一下 

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

解释:p为指针变量,加0x1就就是加一,也就是跳过一个结构体(20个字节),所以结果为0x100014

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

解释:这里由于强制类型转换了为unsigned long型,所以这里的加0x1就是加1,所以结果为0x100001

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

解释:这里由于强制类型转换了为unsigned int*型,这里加一就只跳了一个整型的,所以加4,结果为0x100004

笔试题三

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;
}

首先我们得明白这个数组在内存中如何存储,如下图所示

bed2bed4256641278a4a77c317ff559b.png

 

 其次我们得知道&a,&a+1,int(a),int(a)+1,以及ptr[-1]与ptr的位置,如下图

4f624dbb64924f53ba5601dbffe861f8.png

 最后我们还得知道需要访问几个字节,因为打印用的%x,所以访问四个字节

facfebbdda9a46a6864b40efe4f6b099.png

所以最后结果为00000004和00000002

笔试题四

#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;
}

 这道题,需要我们注意的是,数组中的元素,(0,1)其实表示的是一个元素为1,这是一个逗号表达式,后面就可以依次类推,结果如下图所示

d4efa681b57f4e1ca02c13df8c92c390.png

 则p[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;
}

这里我借一位大牛的图来跟大家讲解一下

395fcff24b134290897608e781f2cc05.png

 则由图所知&p[4][2]-&a[4][2]的大小为-4,如果用%p打印的话,打印的就是-4的补码,转换如下

//	//10000000000000000000000000000100---原码
//	//11111111111111111111111111111011---反码
//	//1111 1111 1111 1111 1111 1111 1111 1100---补码
//	//F    F    F    F    F    F    F    C

所以结果为

c9a7b5cd0500451f8f4cf5b9e6a2e8d6.jpeg

笔试题六 

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;
}

这道题配合下图,以及前面所学我就不进行讲解了

7aeb1c0efb004b3cae9924edf445f0d3.png

 结果为10,5

笔试题七 

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

这道题我们得明白,a是一个指针数组,a里面每一个字符串都是一个指针

b4134539d3f64494a9a751490e3924de.png

 那么这道题就简单了,

ddbc9392b7d64560a6da43361a80595f.png

 则*pa就就是字符串"work"的地址,所以结果就为work

总结

至此,指针进阶部分就讲解完了,有不对或者不懂的地方记得评论去留言或私信博主!!!

博主制作不易,记得三连。以便关注博主后续创作!!!

 

 

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

遇事问春风乄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值