当前位置: 首页 > news >正文

指针和数组笔试题解析

文章目录

  • 前言
  • 试题1
  • 试题2
  • 试题3
  • 试题4
  • 试题5
  • 试题6
  • 试题7
  • 试题8
  • 试题9
  • 试题10
  • 试题11
  • 试题12
  • 试题13
  • 试题14


前言

记录一些关于指针和数组的笔试题,加强对于指针和数组的理解!!!


试题1

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

sizeof关键字用于计算变量或类型、常量在内存中所占空间大小;
在做题之前我们先明白一个问题;
数组名在什么情况先代表整个数组、又在什么情况下代表数组首元素地址;

代表整个数组:
1、数组名单独放在sizeof内部,表示算的是整个数组的内存大小;
2、&数组名,表示的是一个数组的指针,该指针指向数组(&要和数组名结合,中间不能有任何“杂质”)
代表数组首元素地址:
不满足以上俩个结论就是代表数组首元素地址;

会过头来我们继续分析该题:
1、sizeof(a)数组名单独放在sizeof内部,此时数组名表示整个数组,因此sizeof求的是整个数组的大小,结果也就是:16;
2、再看a+0;数组名没有单独放在sizeof内部,也没有&,因此此时数组名代表首元素地址,既然是地址,那么地址也就是固定的,结果:4/8;
3、*a,数组名没有单独放在sizeof内部,也没有&,因此此时数组名代表首元素地址,对首元素地址解引用,自然也就是int型,结果:4
4、看a+1;数组名没有单独放在sizeof内部,也没有&,因此此时数组名代表首元素地址,既然是地址,那么地址也就是固定的,结果:4/8;
5、a[1];数组名没有单独放在sizeof内部,也没有&,因此此时数组名代表首元素地址,a[1],代表下标为1的元素,该元素为int型,结果:4;
6、&a;数组名没有单独放在sizeof内部,但是有&,此时数组名代表的是整个数组,只不过是整个数组的指针,也就是指向该数组,既然是指针,大小也就自然而然的固定了,结果:4/8;
7、
&a;数组名没有单独放在sizeof内部,但是有&,因此&a代表的是取出整个数组的指针, *代表对指针解引用,由于该指针指向整个数组,那么解引用出来,也就代表着整个数组,自然也就是计算的整个数组的大小,结果:16;
8、&a+1;数组名没有单独放在sizeof内部,但是有&,&a是个数组指针指向整个数组,&a+1,跳过一个数组的大小,既然是指针,大小自然固定,结果:4/8;
9、&a[0];数组名没有单独放在sizeof内部,&也没有和数组名结合;a[0]代表下标为0的元素,&表示取出这个位置的地址,最终sizeof计算的是地址,结果:4/8;
10、&a[0]+1;数组名没有单独放在sizeof内部,也没有&,&a[0]+1,表示下表为1的元素地址,sizeof计算的是地址,结果:4/8;
运行结果:
在这里插入图片描述

试题2

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

1、arr;数组名单独放在sizeof内部,此时数组名表示整个数组,sizeof计算的也是整个数组的大小,结果:6;
2、arr+0;数组名没有单独放在sizeof内部,此时数组名表示首元素地址,地址+0还是地址,自然结果就就是:4/8;
3、*arr;数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,对地址解引用,访问其指向对象,它指向对象为char型,sizeof计算char型,大小为:1;
4、arr[1];数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址;arr[1]表示访问下标为1的元素,类型为char,结果:1
5、&arr;数组名没有单独放在sizeof内部,&和数组名结合,此时数组名代表数组整个数组;&arr代表整个数组的指针,结果:4/8;
6、&arr+1;与上述一样,&arr既然是指针,&arr+1,自然也是指针,结果:4/8;
7、&arr[0]+1;arr先和[ ]结合,于是首先排除数组名代表整个数组的可能,因此此时数组名代表数组首元素地址,&arr[0]+1,就代表取出下标为0的元素的地址然后+1,结果还是地址,结果:4/8;
运行结果:

在这里插入图片描述

试题3

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

strlen函数用于统计字符串长度,遇到‘\0’结束(不计算‘\0’);
1、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,由于我们不知道什么时候能遇到’\0’,strlen也就不知道什么时候结束,一切全靠编译器决定,因此结果:随机值;
2、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,结果:随机值;
3、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,*arr表示访问下标0的元素,即为:‘a’,阿斯克码值为97,也就是我们要求strlen从地址为97的位置开始计算,此时编译器会报错,因为我们非法访问内存了,97地址的空间不属于我们,属于操作系统,我们无权对其进行读写!结果:err
4、arr[1];与上述一样的问题,结果:err;
5、&arr;代表整个数组,也就是指向该数组的指针由于指向该数组的指针与数组首元素地址在值的方面上是一样的,因此,该运行结果与1等效,结果:随机值;
6、&arr+1;&arr代表数组指针,+1代表跳过一个数组,表示从该位置统计字符,由于‘\0’依旧不明确,结果:随机值;
7、&arr[0]+1;arr先于[ ]结合srr也就代表数组首元素地址,&arr[0]+1,表示是下标为1的位置处的地址,也就是从该位置开始统计字符个数,同样是无法预料’\0’位置,结果也即是:随机值;
由于3、4会造成编译器崩溃,我们先测试3、4:
在这里插入图片描述

在这里插入图片描述
接下来我们测试能正常输出的:
在这里插入图片描述

试题4

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

1、数组名单独放在sizeof内部,数组名代表整个数组,故sizeof计算的是整个数组的大小,结果:7;
2、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,结果:4/8;
3、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,结果:1;
4、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,结果:1;
5、数组名没有单独放在sizeof内部,&和数组名结合,此时数组名代表数组,但还是指针,结果:4/8;
6、数组名没有单独放在sizeof内部,&和数组名结合,此时数组名代表数组,&arr+1跳过一个数组,但还是指针,结果:4/8;
7、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,&arr[0]+1,但还是指针,结果:4/8;
8、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,字符串又是以‘\0’结尾的,我们明确直到‘\0’位置,结果:6;
9、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,字符串又是以‘\0’结尾的,我们明确直到‘\0’位置,结果:6;
10、数组名没有单独放在sizeof内部,&也没和数组名结合,此时数组名代表数组首元素地址,*arr表示访问下标0的元素,即为:‘a’,阿斯克码值为97,也就是我们要求strlen从地址为97的位置开始计算,此时编译器会报错,因为我们非法访问内存了,97地址的空间不属于我们,属于操作系统,我们无权对其进行读写!结果:err;
11、同10;
12、&arr;代表整个数组,也就是指向该数组的指针由于指向该数组的指针与数组首元素地址在值的方面上是一样的,因此,该运行结果与1等效,结果:6;
13、&arr+1;&arr代表数组指针,+1代表跳过一个数组,表示从该位置统计字符,由于‘\0’不明确,结果:随机值;
14、&arr[0]+1;arr先于[ ]结合srr也就代表数组首元素地址,&arr[0]+1,表示是下标为1的位置处的地址,也就是从该位置开始统计字符个数,预料的到’\0’位置,结果即是:5;
由于10、11会造成编译器崩溃,我们先测试10、11:
在这里插入图片描述
在这里插入图片描述
能输出结果的运行:
在这里插入图片描述

试题5

int main()
{
	const 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));
	return 0;
}

p里面存的是字符的首元素地址(不是数组名!!!):
1、p是一个char*指针,结果:4/8;
2、p+1,还是一个指针,结果:4/8;
3、*p访问字符串首元素,数组首元素为char类型,结果:1;
4、p[0],访问字符串首元素,数组首元素为char类型,结果:1;
5、&p是个二级指针,指向p这块空间,二级指针也是指针,结果:4/8;
6、&p是个二级指针,&p+1也是个二级指针,结果:4/8;
7、&p[0]+1,p先和[ ]结合,先访问,在取出该空间的地址,地址+1还是地址,结果:4/8;
8、p数组首元素,‘\0’位置明确,结果:6;
9、p+1,指向第二个元素,结果:5;
10、*p,非法访问,报错,结果:err;
11、同上;
12、&p,取出p空间的地址,从此位置统计字符,由于不知’\0’位置,结果:随机值;
13、同上;
14、&p[0]+1,从第二个元素开始统计字符,结果:5;

10、11运行结果:
在这里插入图片描述
在这里插入图片描述
可以运行处结果的:
在这里插入图片描述

试题6

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//12*4
	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
	return 0;
}

我们直到二维数组是由多个相同类型的一维数组组成起来的:
1、数组名单独在sizeof内部使用,表示整个数组,计算的也即是整个数组的大小,结果:48;
2、数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,a[0] [0]表示0行0列的元素,元素为int型,结果:4;
3、数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,二维数组的首元素是一个一维数组,因此此时数组名表示一个一维数组指针,同时a[0]等价于
*(a+0);我们同时再想一想,我们是怎样得到一个数组指针的,是不是通过&数组名,现在我们对数组指针解引用,是不是就相当于访问数组名嘛,现在数组名单独放在sizeof内部,表示整个一维数组,这个一维数组有4个元素,因此大小为:16;
4、上面说了a[0]是第一个一维数组的数组名,现在数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,首元素地址加1还是地址,也就是a [0][1]的地址,结果:4/8;
5、a[0]是第一个一维数组的数组名,现在数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,首元素地址加1还是地址,首元素地址加1还是地址,也就是a [0][1]的地址,对其解引用自然访问的是a[0][1],结果:4;
6、数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,也就是一个数组指针,数组指针+1,跳过一个数组,但还是指针,结果:4/8;
7、数组名没有单独放在sizeof内部,也没有&,此时数组名表示首元素地址,也就是一个数组指针,数组指针+1,跳过一个数组,但还是指针,也就是第二个一维数组的数组指针,我们对其解引用,自然拿到的就是第二个一维数组的数组名,数组名单独放在sizeof内部,自然计算的是整个数组大小:16;
8、&a[0] + 1;数组名表示首元素地址,也就是第一个一维数组的数组指针,[0],表示拿到第一个一维数组的数组名,现在我们再对数组名&又拿到了第一个一维数组的数组指针,在+1,跳过一个数组,拿到第二个一维数组的数组指针,既然是指针,结果自然就是:4/8;
9、* (&a[0] + 1)),接着上面,我们拿到了第二个一维数组数组指针,对其解引用自然拿到的就是第二个一维数组的数组名,数组名单独放在sizeof内部表示整个数组,结果自然就是:16;
10、*a,数组名表示首元素地址,也就是第一个一维数组的数组指针,对其解引用,拿到的自然是第一个一维数组的数组名,数组名单独放在sizeof内部,表示整个数组,结果:16;
11、虽然a[3]已经越界了,但是我们并没有去访问它,所以不算是越界访问,此时编译器把它当作与合法范围内的一维数组相同类型的数组,a[3]拿到的依旧是第4个一维数组的数组名,数组名单独放在sizeof内部,表示整个数组,结果:16;
运行结果:
在这里插入图片描述

试题7

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

数组名与&结合表示整个数组指针+1跳过整个数组,是个数组指针,现在被强转为int*;
在这里插入图片描述
运行结果:
在这里插入图片描述

试题8

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);//作对照
	printf("%p\n", p + 0x1);//100014
	printf("%p\n", (unsigned long)p + 0x1);//100001
	printf("%p\n", (unsigned int*)p + 0x1);//100004
	return 0;
}

p是一个结构体指针,故p+1,跳过其所指向类型大小,故p+0x1,实际上是+20;
p原本是个指针,现在被强转为无符号长整型,也就是是个普通整数,普通整数+1,实际上就是+1;
p原本是个结构体指针,现被强转为int*指针,指针+1跳过其所指类型大小,实际上p+1,加的其实是20;
运行结果:
在这里插入图片描述

试题9

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

ptr1:&a表示数组指针,数组指针+1,跳过一个数组,现在被强转为int*
ptr2:数组名表示首元素地址,被转换为无符号整型在+1,也就是普通加一,也就是跳过一个字节;
在这里插入图片描述
运行结果:
在这里插入图片描述

试题10

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

我们在数组中发现了逗号表达式,我们先对逗号表达式处理一下,
int a[3][2]={1,3,5};
a[0],表示第一个一维数组的数组名,此时数组名没有单独放在sizeof内部,也没有&,因此数组名表示第一个一维数组首元素地址,p[0]访问第一个一维数组的第一个元素,也就是1;
运行结果:
在这里插入图片描述

试题11

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单独使用表示数组首元素地址,也就是int ()[5]类型;
p也是一个数组指针,int(*)[4]类型;
p=a,会有警告,但是语法没错;
a+1,实际跳过20个字节;
p+1,实际跳过16个字节;
a[4]跳过80个字节,解引用,表示数组名;
p[4]跳过64个字节,解引用,表示数组名;
a[4][2],在a[4]的基础上再跳2
4个字节;
p[4][2],在p[4]的基础上再跳2*4个字节;
故实际上a[4][2]的地址:88
故实际上p[4][2]的地址:72;
故&p[4][2] - &a[4][2]=-4;(指针相减表示指针之间元素个数)
%p打印无符号整数,%d打印有符号整数;
运行结果:

在这里插入图片描述

试题12

小试牛刀:

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));//10,5
    return 0;
}

试题13

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

解决这个体的最好办法就是画图:
在这里插入图片描述
运行结果:
在这里插入图片描述

试题14

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

有了上一题的基础,这一题就会简单很多:
还是画图:
在这里插入图片描述
运行结果:
在这里插入图片描述

相关文章:

  • 人脸检测5种方法
  • SparkSQL 总结(未完待续)
  • 51单片机入门——数模\模数转换
  • 【毕业设计】 单片机自动写字机器人设计与实现 - 物联网 嵌入式 stm32
  • 花边新闻获取易语言代码
  • HTML5入门(1)——HTML基础
  • 计算机网络体概念
  • redis底层都有哪些数据结构?带你了解redis是如何存储数据的
  • 通道分离与合并、彩色图转换为灰度图、二值化
  • C语言经典算法实例4:判断回文数
  • 基于php+mysql的菜品食谱美食网
  • upload-labs靶场通关指南(第1-3关)
  • Android Studio 利用系统签名打包apk
  • 升级打怪课堂的题库更新了!
  • Excel·VBA数组排列函数
  • 【Linux系统编程】快速查找errno错误码信息
  • 0x05 Python数据分析,Anaconda八斩刀
  • C语言笔记(第一章:C语言编程)
  • dva中组件的懒加载
  • Git同步原始仓库到Fork仓库中
  • Golang-长连接-状态推送
  • Lucene解析 - 基本概念
  • Object.assign方法不能实现深复制
  • PV统计优化设计
  • Rancher-k8s加速安装文档
  • spring boot 整合mybatis 无法输出sql的问题
  • supervisor 永不挂掉的进程 安装以及使用
  • 包装类对象
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 关于使用markdown的方法(引自CSDN教程)
  • 简单易用的leetcode开发测试工具(npm)
  • 开源SQL-on-Hadoop系统一览
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 普通函数和构造函数的区别
  • 前端存储 - localStorage
  • 深入浅出webpack学习(1)--核心概念
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 微信小程序--------语音识别(前端自己也能玩)
  • 用jQuery怎么做到前后端分离
  • - 转 Ext2.0 form使用实例
  • 转载:[译] 内容加速黑科技趣谈
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #laravel 通过手动安装依赖PHPExcel#
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (Java数据结构)ArrayList
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (三)c52学习之旅-点亮LED灯
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四)JPA - JQPL 实现增删改查