18.有关数组和指针的笔试题

一.数组面试题

0.基础须知

一般情况下,数组名是首元素地址
但是,有两个例外:
1.sizeof(数组名)————数组名单独放到整个数组里面,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名也表示数组,取出的是数组的地址

sizeof是操作符,只关注占用空间,不关注类型,单位是字节
strlen是库函数,关注字符中\0之前出现了多少个字符,它只针对字符串,就算的是长度,调用strlen时,得传给他一个地址,从这个位置开始统计字符,知道\0.

1.题目1——一位数组中sizeof的计算

//一维数组
	int a[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(a));//数组名a单独放到sizeof里面,计算的是整个数组的大小   4*4=16字节
	printf("%d\n", sizeof(a + 0));//这里的数组名a不是单独放到sizeof里面,所以它代表首元素地址,a+0还是首元素地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*a)); //数组名表示首元素地址,*a就相当于首元素,首元素的大小是 4 个字节
	printf("%d\n", sizeof(a + 1));//数组名表示首元素地址,a+1,就表示第二个元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(a[1]));//int类型元素大小为 4 个字节
	printf("%d\n", sizeof(&a));//&a取到的就是数组 a的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*&a));
	//理解1:*和&相互抵消,*&a就相当于a,sizeof(a)就是16
	//理解2:&a取到的是数组a的地址,其类型为 int(*)[4],对它解引用之后,拿到的就是整个数组,大小就是 16 个字节
	printf("%d\n", sizeof(&a + 1));//&a取到的就是数组 a的地址,&a+1是跳过整个数组的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&a[0]));//&a[0]取到的是元素a[0]的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]取到的是元素a[0]的地址,&a[0] + 1就是a[1]的地址,是地址就是4/8个字节

2.题目2——字符数组中 sizeof 和 strlen 的计算

int main()
{
	//字符数组
	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\n", sizeof(arr));//sizeof(数组名)计算整个数组的大小   6字节
	printf("%d\n", sizeof(arr + 0));//数组名表示首元素地址,a+0表示的还是首元素的地址  ,4/8字节
	printf("%d\n", sizeof(*arr));//数组名表示首元素地址,*arr就表示首元素  大小为 1个字节
	printf("%d\n", sizeof(arr[1]));//计算元素arr[1]的大小  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个字节


    printf("%d\n", strlen(arr));//arr是首元素地址,但是arr数组中没有\0,计算的时候就不知道什么时候停止,结果是:随机值
	printf("%d\n", strlen(arr + 0)); //arr是首元素地址,arr+0还是首元素地址,结果是:随机值
	printf("%d\n", strlen(*arr));  //err
	//arr是首元素地址,*arr是首元素,也就是说传给strlen的是'a',a的ascii码值是97,strlen会把97作为起始地址取统计字符串,会形成内存访问冲突
	printf("%d\n", strlen(arr[1]));//err 和上面一样,内存访问冲突
	printf("%d\n", strlen(&arr));
	//&arr是arr的数组地址,虽然类型和strlen的参数类型有所差异,但是传参过去后,还是从第一个字符的位置向后计算字符,结果是:随机值
	printf("%d\n", strlen(&arr + 1));
	//&arr是arr的数组地址,&arr+1是跳过整个数组后的地址。结果是:随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值
}

3.题目3——用指针形式初始化字符串时 sizeof 和strlen的计算

int main()
{
	char *p = "abcdef";//用这种方式创建的字符串,末尾都会有'\0',即有 abcdef\0,指针p存放的1是字符串的首元素地址
	printf("%d\n", sizeof(p));//p是一个指针变量,指针的大小为 4/8个字节
	printf("%d\n", sizeof(p + 1));//p+1就是'b'的地址,是地址大小就是4/8个字节
	printf("%d\n", sizeof(*p));//p代表的是'a'的地址,*p就是a,a的大小为一个字节
	printf("%d\n", sizeof(p[0]));//p[0]就相当于*(p+0),即*p,   1个字节
	printf("%d\n", sizeof(&p));//&p也是地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&p + 1));//&p也是地址,&p+1也是地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&p[0] + 1));//&p[0]是'a'的地址,&p[0] + 1就是'b'的地址,是地址就是4/8个字节

	printf("%d\n", strlen(p));//p中存放的是'a'的地址,strlen(p)就从'a'的位置开始计算,知道遇见'\0',长度为6
	printf("%d\n", strlen(p + 1));//p+1代表'b'的地址,strlen(p+1)就从'b'的位置开始计算,知道遇见'\0',长度为5
	printf("%d\n", strlen(*p));//err  n内存访问冲突
	printf("%d\n", strlen(p[0]));//err  n内存访问冲突
	printf("%d\n", strlen(&p));//随机值
	printf("%d\n", strlen(&p + 1));//随机值
	printf("%d\n", strlen(&p[0] + 1));// 5
}

4.题目4——二维数组中sizeof的计算

记住:

  1. 二维数组中,a[i] 代表的是第 i 行的数组名,它就符合一维数组的规律
  2. *(a+i) = a[i]
int main()
{
	//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//sizeof(数组名)计算的是整个数组的大小  12*4=48字节
	printf("%d\n", sizeof(a[0][0]));//数组元素为int类型,大小为4个字节
	printf("%d\n", sizeof(a[0]));//a[0]表示第一行的数组名,sizeof(数组名)计算的是整个第一行数组的大小  4*4=16字节
	printf("%d\n", sizeof(a[0] + 1));//a[0]是第一行的数组名,数组名代表首元素地址,a[0]+1就代表第一行第一个元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*(a[0] + 1)));//(a[0] + 1)代表第一行第一个元素的地址,*(a[0] + 1)就是第一行第一个元素,大小为4个字节
	printf("%d\n", sizeof(a + 1));//数组名表示首元素地址,即第一行的地址,而,a+1 就代表第二行的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*(a + 1)));//*(a+1)就相当于a[1],即第二行的数组名,sizeof(数组名)计算的是整个整个第一行数组的大小  4*4=16字节
	printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]就表示第一行的地址,则 &a[0] + 1 就表示第二行的1地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*(&a[0] + 1))); //&a[0] + 1表示第二行的地址,即a+1,则*(a+1)就相当于a[1],即表示第二行的数组名,
	                                      //sizeof(数组名)计算的是整个第二行数组的大小  4*4=16字节
	printf("%d\n", sizeof(*a));//数组名表示首元素地址,*a=*(a+0)=a[0],sizeof(数组名)计算的是整个第1行数组的大小  4*4=16字节
	printf("%d\n", sizeof(a[3]));//虽然a[3]越界了,但是没关系  4*4=16字节
}

二.指针面试题

题目1

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);
	//&a取到的是数组的地址,其地址类型为:int(*)[5]
	//&a+1即跳过整个数组
	//然后将她强制类型转换成(int*)数据
	printf("%d,%d", *(a + 1), *(ptr - 1));
	//*(a+1)就相当于a[1]
	return 0;
}
//程序的结果是什么?

在这里插入图片描述

即输出结果为:2 和 5

题目2

//这里告知结构体的大小是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);
	//结构体指针加1,就跳过整个结构体,即打印 00100014
	printf("%p\n", (unsigned long)p + 0x1);
	//将结构体指针 p 强制类型转换为 unsigned long 型数据,unsigned long类型是数字,数字加1就是加1,即00100001
	printf("%p\n", (unsigned int*)p + 0x1);
	//将结构体指针 p 强制类型转换为 unsigned long * 型数据,unsigned long *数据的步幅为4,加1就是加4,即00100004
	return 0;
}

题目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);//以16进制的形式打印
	//ptr1[-1]比较简单,容易得出为4
	//*ptr2的计算涉及到小端存储模式,看图
	return 0;
}

在这里插入图片描述

打印结果为:4 和 2000000

题目4

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	//注意:数组里面de(  , )是逗号表达式数组里面真实存储的是: a[3][2] = { 1, 3, 5};
	int *p;
	p = a[0];
	//a[0]表示二维数组的首元素地址,即p =*(a+0)
	printf("%d", p[0]);//p[0]=*(*(a+0)+0),即a[0][0],故打印 1
	return 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;
}

在这里插入图片描述

题目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

题目7

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

在这里插入图片描述

题目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

第一个打印分析:
在这里插入图片描述
第二个打印分析:
在这里插入图片描述

第三个和第四个打印:
将 *cpp[-2] + 3 翻译成 **(cpp-2)+3
将 cpp[-1][-1] + 1 翻译成 *( *(cpp-1)-1)+1
然后按照前面的方法分析就行

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值