【数组和进阶指针经典笔试题12道】这些题,满足你对数组和指针的所有幻想,come on !

 前言: 刷题和面试兼顾还得看你啊-牛客网

近几年互联网受疫情影响,许多互联网都使用牛客网在线笔试招人

很多同学因为不熟悉牛客网的环境和使用,最后在线笔试面试中屡屡受挫

牛客网提供了语言巩固,算法提高等在线OJ题,更有面试真题,大厂内推!

链接附上点击链接注册牛客网

牛客网这么好用,但是下面几个关于牛客网的知识你了解过吗?

  • 你知道你OJ过不了,牛客网几种经典的英文报错提示的含义吗?
  • 你知道牛客网的OJ分为IO型和接口型吗?
  • 你使用过牛客网的调试功能吗?

众所周知,指针是C语言的灵魂,很多人就是倒在指针的脚下。今天,我来带大家看一看指针在笔试中是怎么考的吧!(提示:本篇博客测试环境是vs-x64,该环境下指针占8个字节)

练习题1

int main()
{
	int a[4] = { 1,2,3,4 };
	printf("%u\n", sizeof(a));//16-sizeof(数组名)-整个数组
	printf("%u\n", sizeof(a+0));//8-不是单独的数组名-数组首元素的地址
	printf("%u\n", sizeof(*a));//4-数组首元素的地址解引用-数组首元素
	printf("%u\n", sizeof(a+1));//8-数组第2个元素的地址
	printf("%u\n", sizeof(a[1]));//4-数组第2个元素
	printf("%u\n", sizeof(&a));//8-整个数组的地址
	printf("%u\n", sizeof(*&a));//16-对整个数组的地址解引用,得到的是整个数组-sizeof(数组名)
	printf("%u\n", sizeof(&a+1));//8-&a是整个数组的地址,+1跳过一个数组,还是一个数组的地址
	printf("%u\n", sizeof(&a[0]));//8-首元素的地址
	printf("%u\n", sizeof(&a[0]+1));//8-第2个元素的地址

	return 0;
}

 练习题2

int main()
{
	char str[5] = { 'a','b','c','d','e' };
	printf("%d\n", sizeof(str));//5-sizeof(数组名)-整个数组
	printf("%d\n", sizeof(str+0));//8-数组首元素的地址
	printf("%d\n", sizeof(*str));//1-数组首元素
	printf("%d\n", sizeof(str[1]));//1-数组第二个元素
	printf("%d\n", sizeof(&str));//8
	printf("%d\n", sizeof(&str[0]+1));//8
	printf("%d\n", sizeof(str[0]+1));//4-字符和整型相加-整型提升
	//等价于printf("%d\n", sizeof('a'+1));//4-整型提升

	return 0;
}

 练习题3

int main()
{
	char str[] = { 'a','b','c','d','e' };
	printf("%d\n", strlen(str));//随机值
	printf("%d\n", strlen(str+0));//随机值

	printf("%d\n", strlen(*str));//strlen('a')-->strlen(97);//野指针
	printf("%d\n", strlen(str[1]));//野指针

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

	return 0;
}

 这里的第三个printf处如果调试的话,这个错误代表的意思就是访问了非法内存(有一些内存地址是没有办法访问的,有一些是允许访问,但是也会进行一定的检测)

关于sizeof和strlen:

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

strlen是库函数,只针对字符串

sizeof只关注占用内存的大小,不在乎内存中放的是什么

sizeof是操作符

练习题4

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//3*4*4=48-整个二维数组
	printf("%d\n", sizeof(a[0]));//8错//4*4=16对 sizeof(一维数组数组名)-整个第一个一维数组
	printf("%d\n", sizeof(a[0]+1));//8-第2个一维数组的地址
	printf("%d\n", sizeof(a[0][0]));//4-第一个一维数组的第1个元素
	printf("%d\n", sizeof(*(a[0]+1)));//4-第一个一维数组的第2个元素
	printf("%d\n", sizeof(*(a+1)));//8错//4*4=16对 sizeof(一维数组数组名)-整个第2个一维数组
	printf("%d\n", sizeof(a+1));//8-第2个一维数组的地址
	printf("%d\n", sizeof(&a[0]+1));//8-第一个一维数组的第2个元素
	printf("%d\n", sizeof(*a));//4*4=16-整个第一个一维数组
	printf("%d\n", sizeof(a[3]));//16-整个第四个一维数组

	return 0;
}

 

练习题5

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

 练习题6

 

struct Test
{
	int num1;
	char* num2;
	short num3;
	char num4[2];
	short num5[4];
}*p;

//假设p的值为0x100000,如下表达式的值分别是多少?
//已知在当前环境下,Test类型的变量大小是20个字节


//考察:指针/整数+1到底是加了多少
int main()
{
	printf("%p\n", p + 0x1);//0x100014
	printf("%p\n", (unsigned long)p + 0x1);//0x100001
	printf("%p\n", (unsigned int*)p + 0x1);//0x100004

	return 0;
}

0x1就是十六进制的1,也就是十进制的1:

 对于第一个p+0x1中p是struct Test* 类型的指针,加1,跳过一个sizeof(struct Test)==20,也就是0x00014大小。

同理第二个p是被强制转换为了unsigned long类型,是一个整数,整数=1就是+1,然后按照%p打印出来,加的因为就是1(没有超过16),所以和在原来的0x10000上加1是一样的。

同理第三个p是被强制转换为了unsigned int*类型,加1,加的是4个字节。

练习题7


int main()
{
	int a[4] = { 1,2,3,4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)(a + 1);
	int* ptr3 = (int*)((int)a + 1);
	int* ptr4 = (int*)((char*)a + 1);
	printf("%x %x %x %x\n\n", ptr1[-1], *ptr2,*ptr3,*ptr4);//

	return 0;
}

 

ptr3得到的方式是:

通过将整型指针强制转换为整型数值,然后加1,最后再强制转换为整型指针;

ptr4得到的方式是:

通过将整型指针强制转换为字符指针,然后加1,最后再强制转换为整型指针。

两个的效果是一样的。 

 练习题8

int main()
{
	int a[3][2] = { (0,1),(2,3),(3,4) };//坑点:逗号表达式
	int* p;
	p = a[0];
	printf("%d\n", p[0]);
	//等价于printf("%d\n", *p);

	return 0;
}

 练习题9

int main()
{
	int a[4][5];
	int(*p)[3];//重点在于这里的3,不是5
	p = a;
	printf("%p %d\n", &p[3][2] - &a[3][2], &p[3][2] - &a[3][2]);

	return 0;
}

 关于-6变FFFFFA:

 练习10

int main()
{
	int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (*(a + 1));
	//等价于int* ptr2 = (int*)(a + 1);

	printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));//10 5

	return 0;
}

 练习11

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

 

练习题12 

int main()
{
	char* c[] = { "ENTRE","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[-1]就是指向的*(cpp-1),就是先指针-1(指向发生改变),然后过桥(找到指针指向的那个目标);

然后这里的虚线就是不会有自增++有副作用

a=a+1;有副作用(a变了)

但是a+1;就没有副作用(a没有变)

 

 

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码上心头

为爱发电

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

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

打赏作者

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

抵扣说明:

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

余额充值