指针和数组笔试题解析

今天,我们一起来解析笔试题,一起走上人生巅峰。我们先来看看关于数组的笔试题。

首先我们要搞清楚数组名的意义( sizeof计算结果的单位是字节):

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

数组笔试题

一维数组

sizeof只关心类型,括号中给出什么类型,sizeof就计算它分配内存的大小。

	//一维数组
	int a[] = { 1, 2, 3, 4 };
	//sizeof(数组名),计算的是整个数组的大小
	printf("%d\n", sizeof(a));//16字节

	//a是首元素的地址,a+0也是地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(a + 0)); //4字节

	//a是首元素地址,*a为首元素,int类型,4字节
	printf("%d\n", sizeof(*a)); //4字节

	//a是首元素地址,a+1为a[1]的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(a + 1)); //4字节

	//a[1]=2,为int类型
	printf("%d\n", sizeof(a[1])); //4字节

	//&a为整个数组的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&a)); //4字节

	//&a为整个数组的地址,*&a就得到整个数组
	printf("%d\n", sizeof(*&a)); //16字节

	//&a为整个数组的地址,&a+1跳过整个数组的那个地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&a + 1)); //4字节

	//&a[0],取a[0]的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&a[0])); //4字节

	//&a[0] + 1,得到的是a[1]的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&a[0] + 1));//4字节

字符数组

	//字符数组
	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; 
	//sizeof(数组名),数组名表示整个数组,计算整个数组的大小,char类型为1个字节
	printf("%d\n", sizeof(arr)); //6字节

	//arr首元素地址,arr+0也为地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(arr + 0)); //4字节

	//arr首元素地址,*arr指向的是首元素,char类型
	printf("%d\n", sizeof(*arr)); //1字节

	//arr[1]为char类型
	printf("%d\n", sizeof(arr[1]));//1字节

	//&arr取整个数组的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&arr)); //4字节

	//&arr为整个数组的地址,&a+1跳过整个数组的那个地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&arr + 1)); //4字节

	//&arr[0],取arr[0]的地址,&arr[0]+1,跳过一个字节,到arr[1]的地址,指针大小为4字节
	printf("%d\n", sizeof(&arr[0] + 1));//4字节

strlen()函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’)。strlen结束的标志是,找到’\0’为止。

	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	
	//arr是首元素的地址,从首元素开始找,直到'\0'停止,但是arr数组中没有'\0'
	//strlen函数就会继续往后面找,直到'\0'停止,我们也不能具体的知道'\0'的位置
	//就会是一个不确定的值
	printf("%d\n", strlen(arr)); //随机值

	//arr+0也是首元素地址,与上面同理
	printf("%d\n", strlen(arr + 0)); //随机值

	//arr是首元素的地址,*arr指向首元素为'a'
	//strlen就会以'a'的ASCII值为地址,向后寻找'\0'
	//这个地址不在我们程序范围内,就会出现野指针的问题,程序就会报错
	printf("%d\n", strlen(*arr)); //error

	//arr[1]为'b',与上面同理
	printf("%d\n", strlen(arr[1])); //error

	//&arr是整个数组的地址,它与arr的值相同,以这个地址继续向后面找'\0' 
	printf("%d\n", strlen(&arr)); //随机值

	//&arr+1是跳过整个数组,'f'后面的地址,继续找'\0'
	printf("%d\n", strlen(&arr + 1)); //随机值

	//&arr[0]是首元素'a'的地址,&arr[0]+1是'b'的地址
	printf("%d\n", strlen(&arr[0] + 1));//随机值
	char arr[] = "abcdef";
	
    //sizeof(arr),arr表示整个数组,计算整个数组的大小
	//数组为   [a][b][c][d][e][f][\0]  char -> 1字节
	printf("%d\n", sizeof(arr));//7字节

	//arr是首元素地址,arr+0还是首元素地址,在32位平台,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(arr + 0));//4字节

	//arr是首元素地址,*arr是指向首元素的地址,*arr为'a'
	printf("%d\n", sizeof(*arr)); //1字节

	//arr[1]='b'
	printf("%d\n", sizeof(arr[1]));//1字节

	//&arr是整个数组的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&arr)); //4字节

	//&arr+1跳过整个数组的那个地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&arr + 1));//4字节

	//&arr[0]+1是arr[1]的地址,在32位平台,指针大小为4字节
	printf("%d\n", sizeof(&arr[0] + 1));//4字节




	//arr是首元素的地址, 从这个地址往后找到'\0'为止
	printf("%d\n", strlen(arr));//6

	//arr+0也是首元素的地址
	printf("%d\n", strlen(arr + 0));//6

	//arr是首元素的地址,*arr指向首元素为'a'
	//strlen就会以a的ASCII值为地址,向后寻找'\0'
	//这个地址不在我们程序范围内,就会出现野指针的问题,程序就会报错
	printf("%d\n", strlen(*arr));//error

	//arr[1]='b',与上面同理
	printf("%d\n", strlen(arr[1])); //error

	//&arr是整个数组的地址,它与arr的值相同,以这个地址继续向后面找'\0' 
	printf("%d\n", strlen(&arr));//6

	//&arr + 1是跳过整个数组的那个地址,此时以这个地址向后找'\0'
	//直到内存中出现'\0'停止,但我们不知道'\0'的具体位置,会是个不确定的值
	printf("%d\n", strlen(&arr + 1));//随机值

	//&arr[0] + 1,是arr[1]的地址,从这个位置找'\0'
	printf("%d\n", strlen(&arr[0] + 1));//5
      char *p = "abcdef"; 

	  //此时的p不是一个数组
	  //"abcdef"是一个常量字符串,p中存储的是'a'的地址
	  //在32位平台,指针大小为4字节
	  printf("%d\n", sizeof(p));//4字节

	  //p+1是'b'的地址,在32位平台,指针大小为4字节
	  printf("%d\n", sizeof(p + 1)); //4字节

	  //p中存储的是'a'的地址,*p指向'a','a'是char类型
	  printf("%d\n", sizeof(*p)); //1字节

	  //p[0] <==> *(p+0) <==> *p  与上面同理
	  printf("%d\n", sizeof(p[0])); //1字节

	  //p中存储的是'a'的地址,&p是p的地址,&p需要一个二级指针来存储
	  //在32位平台,指针大小为4字节
	  printf("%d\n", sizeof(&p)); //4字节

	  //&p是p的地址,&p+1跳过整个p (char *),&p+1还是地址
	  printf("%d\n", sizeof(&p + 1)); //4字节

	  //p[0] <==> *(p+0) <==> *p   *p指向'a'
	  //&p[0]是'a'的地址,&p[0] + 1是'b'的地址
	  printf("%d\n", sizeof(&p[0] + 1));//4字节



	  //p中存储的是'a'的地址,从'a'开始往后面找'\0'
	  //"abcdef" ->  a b c d e f \0
      printf("%d\n", strlen(p)); //6

	  //p+1是'b'的地址,从'b'开始往后面找
	  printf("%d\n", strlen(p + 1));//5

	  //p中存储的是a的地址,*p指向'a'
	  //strlen就会以a的ASCII值为地址,向后寻找'\0'
	  //这个地址不在我们程序范围内,就会出现野指针的问题,程序就会报错
	  printf("%d\n", strlen(*p)); //error
	  
	  //p[0] <==> *(p+0) <==> *p,*p指向'a',与上面同理
	  printf("%d\n", strlen(p[0]));//error

	  //p中存储的是'a'的地址,&p是p的地址
	  //我们不知道'\0'的位置,所以是个随机值
	  printf("%d\n", strlen(&p));//随机值

	  //&p + 1跳过整个p的地址,我们也不知道'\0'的位置
	  printf("%d\n", strlen(&p + 1)); //随价值

	  //p[0] <==> *(p+0) <==> *p,*p指向'a'
	  //&p[0]是'a'的地址,&p[0] + 1是'b'的地址 
	  printf("%d\n", strlen(&p[0] + 1));//5  

二维数组

	  //二维数组 
	  int a[3][4] = {0};  
	  //sizeof(a),a表示整个数组,计算整个数组的大小
	  //总共有12个元素,每个元素都是int型
	  printf("%d\n",sizeof(a)); //48

	  //a[0][0] -> 是一个元素,元素类型为int
	  printf("%d\n",sizeof(a[0][0]));//4

	  //a[0]是第一行元素数组名
	  //sizeof(),括号中单独放数组名,计算整个数组的大小
	  printf("%d\n",sizeof(a[0])); //16

	  //a[0]+1不是单独放,所以不是计算整个数组的大小
	  //a[0]是数组名,a[0]是第一行一维数组首元素地址
	  //a[0]+1就是a[0][1]的地址,在32位平台,指针大小为4字节
	  printf("%d\n",sizeof(a[0]+1)); //4

	  //a[0]+1是a[0][1]的地址,*(a[0]+1)就是a[0][1],int类型
	  printf("%d\n",sizeof(*(a[0]+1))); //4

	  //a是二维数组名,数组名是首元素地址
	  //二维数组的首元素就是第一行一维数组
	  //a就是第一行一维数组地址,a+1跳过第一行一维数组,是第二行的数组地址
	  printf("%d\n",sizeof(a+1));//4

	  //a+1是第二行的数组地址,*(a+1)是第二行的数组 
	  printf("%d\n",sizeof(*(a+1))); //16

	  //&a[0]是第一行一维数组地址&a[0]+1
	  //&a[0]+1跳过第一行一维数组,是第二行的数组地址
	  printf("%d\n",sizeof(&a[0]+1)); //4

	  //&a[0]+1是第二行的数组地址
	  //*(&a[0]+1)是第二行的数组
	  printf("%d\n",sizeof(*(&a[0]+1))); //16

	  //a是第一行一维数组地址
	  //*a是第一行数组
	  printf("%d\n",sizeof(*a)); //16 

	  //二维数组a[3][4],有a[0],a[1],a[2]
	  //a[3]已经越界了,但是sizeof只关注类型
	  //如果数组a[3][4],有a[3],那么a[3]和a[2]的类型相同,都是数组名
	  //sizeof(),括号中单独放数组名,计算整个数组的大小
	  printf("%d\n", sizeof(a[3])); //16 

指针笔试题

笔试题一

	int a[5] = { 1, 2, 3, 4, 5 };  
	//&a是数组地址,&a+1跳过整个数组,指针指向元素5后面的地址
	//(int *)(&a + 1)将数组地址强制转化为整形地址
	int *ptr = (int *)(&a + 1);

	//a是数组名,数组名是首元素地址,a[0]的地址
	//a+1是a[1]的地址,*(a + 1)是a[1]=2
	//ptr指向5后面的地址,ptr-1指向元素5的地址
	//*(ptr - 1)是5
	printf("%d,%d", *(a + 1), *(ptr - 1));  //2   5

笔试题二

//这里告知结构体的大小是20个字节 
struct Test 
{    
	int Num;    
	char *pcName;    
	short sDate;   
	char cha[2];    
	short sBa[4]; 
}*p;
	//假设p 的值为0x100000。 如下表表达式的值分别为多少? 

    //0x1是16进制,化为十进制是1   p+1
    //结构体的大小是20个字节,p是结构体指针
    //p+1 -> p+20字节 ->  20的16进制是0x00000014
    //0x100014
	printf("%p\n", p + 0x1);  //0x100014

	//(unsigned long)p 将p强制转换为无符号整数,现在0x100000就是一个整数
	// 0x100000+0x1 -> 0x100001  
    printf("%p\n", (unsigned long)p + 0x1); //0x100001

	//(unsigned int*)p 将p转化为int* ,p+1 ,p+4字节 4的16进制是4
	//0x100004
    printf("%p\n",  p+ 0x1);//0x100004 

笔试题三

	int a[4] = { 1, 2, 3, 4 };

	//&a是数组地址,&a+1,跳过整个数组,指针指向元素4后面的地址
	//(int *)(&a + 1)将指针指向元素4后面的地址强制转化为int*
	//ptr1[-1] -> *(ptr1-1)
	//ptr1-1指向元素4的地址,*(ptr1-1)就是元素4
	//要16进制输出,0x4
	int *ptr1 = (int *)(&a + 1);

	//a是首元素地址,(int)a 将首元素地址强制转化为整数
	//(int *)((int)a + 1),相当于在首元素地址加一个字节
	//在vs编译器中,数组在内存中的存储是小端存储 01 00 00 00 02 00 00 00 03 00 00 00...
	//首元素的地址是01的地址,首元素地址+一个字节的地址就是01后面紧跟着00的地址
	//此时的ptr2是整形指针,*ptr2访问4个字节,00 00 00 02,小端存储就要小端拿回来 02 00 00 00
	//16进制输出,0x2000000
	int *ptr2 = (int *)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);//4  0x2000000

笔试题四

	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	//a中是逗号表达式,实际上数组中的元素a[3][2]={1,3,5}
	int *p;
	p = a[0];
	//a[0]是第一行一维数组名,是首元素地址,a[0][0]的地址
	//p[0] -> *(p+0) ->*p -> a[0][0] ->1
	printf("%d", p[0]); //1

笔试题五

	int a[5][5];    
	int(*p)[4];    
	p = a;   
	//a是二维数组名,是首元素地址,二维数组的首元素是第一行数组
	//a是第一行数组地址,第一行数组有5个元素
	//p为数组指针,只能接受4个元素的一维数组地址
	//指针-指针就是中间所隔元素的个数
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//0xFFFFFFFC -4    

    详解见下图

在这里插入图片描述
笔试题六

	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

	//&aa是二维数组地址,&aa+1跳过整个二维数组,元素10后面的地址
	//ptr1-1是元素10的地址,*(ptr1-1)是元素10
	int *ptr1 = (int *)(&aa + 1);

	//aa是二维数组名,是第一行一维数组地址
	//aa+1跳过第一行数组,到第二行数组地址
	//*(aa + 1)是第二行的首元素地址
	//ptr2 - 1是元素5的地址,*(ptr2 - 1)是元素5
	int *ptr2 = (int *)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10 5

笔试题七

	char *a[] = { "work", "at", "alibaba" };  
	char**pa = a;
	pa++;    
	printf("%s\n", *pa);//at

    详解如下图

  笔试题八

    char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
	char**cp[] = { c + 3, c + 2, c + 1, c };
	char***cpp = cp;    
	printf("%s\n", **++cpp);//POINT
	printf("%s\n", *--*++cpp + 3); //ER   
	printf("%s\n", *cpp[-2] + 3);  //ST  
	printf("%s\n", cpp[-1][-1] + 1);//EW

在这里插入图片描述

总结

在我们遇到sizeof(),一定要注意括号里的类型意义,strlen要注意起始地址。

做题的时候要仔细读题,注意数组中的逗号表达式,还要注意大端或小端的存储方式。我们要明白二维数组首元素是什么,这些题还需要多多揣摩,才能更好的理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值