c语言刷题小练——指针和数组

1. 指针和数组面试题的解析

1.1 一维数组

答案4/8的意思是32位机器上显示4,64位机器上显示8

int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//数组名a单独放在sizeof内部,计算的整个数组的大小,单位是字节,4*4 = 16
printf("%d\n", sizeof(a + 0));//a表示的首元素的地址,a+0还是数组首元素的地址,是地址大小4/8(32位机器上显示4,64位机器上显示8)
printf("%d\n", sizeof(*a));//a表示的首元素的地址,*a就是对首元素的地址的解引用,就是首元素,大小是4个字节
printf("%d\n", sizeof(a + 1));//a表示的首元素的地址,a+1是第二个元素的地址,是地址,大小就4/8个字节
printf("%d\n", sizeof(a[1]));//a[1]是数组的第二个元素,大小是4个字节
printf("%d\n", sizeof(&a)); //&a 表示是数组的地址,数组的地址也是地址,地址大小就是4/8字节
printf("%d\n", sizeof(*&a));//可以理解为*和&抵消效果,*&a相当于a,sizeof(a)是16
//&a -> int(*)[4]
//&a是数组的地址,它的类型是int(*)[4]数组指针,如果解引用,访问的就是4个int的数组,大小是16个字节
printf("%d\n", sizeof(&a + 1));//&a是数组的地址,&a+1 跳过整个数组后的地址,是地址就是4/8
printf("%d\n", sizeof(&a[0]));//&a[0]取出数组第一个元素的地址,是地址就是4/8
printf("%d\n", sizeof(&a[0] + 1));//&a[0]+1就是第二个元素的地址,是地址大小就是4/8个字节

1.2 字符数组

//sizeof只关注占用空间的大小,单位是字节
//sizeof不关注类型
//sizeof是操作符

//strlen关注的字符串中\0的为止,计算的是\0之前出现了多少个字符
//strlen指针对字符串
//strlen是库函数

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//arr作为数组名单独放在sizeof内部,计算的整个数组的大小,单位是字节,6
printf("%d\n", sizeof(arr + 0));//arr就是首元素的地址,arr+0还是首元素的地址,地址大小就是4/8
printf("%d\n", sizeof(*arr));//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,跳过了整个数组,&arr+1还是地址,地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是第一个元素的地址,&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,strlen需要的是一个地址,从这个地址开始向后找字符,直到\0,统计字符的个数。
//但是*arr是数组的首元素,也就是'a',这是传给strlen的就是'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));//随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
char arr[] = "abcdef";
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

printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr+0));//6
printf("%d\n", strlen(*arr));//*arr是数组的首元素,也就是'a',这是传给strlen的就是'a'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
printf("%d\n", strlen(arr[1]));//同上一个
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr+1));//+1跳过字符串,随机值
printf("%d\n", strlen(&arr[0]+1));//5
char *p = "abcdef";
printf("%d\n", sizeof(p)); //p是一个指针变量,sizeof(p)计算的就是指针变量的大小,4 / 8个字节
printf("%d\n", sizeof(p + 1));//p是指针变量,是存放地址的,p+1也是地址,地址大小就是4/8字节
printf("%d\n", sizeof(*p));//*p访问的是1个字节
printf("%d\n", sizeof(p[0]));//p[0]--> *(p+0) -> *p   1个字节
printf("%d\n", sizeof(&p));//&p也是地址,是地址就是4/8字节,&p是二级指针
printf("%d\n", sizeof(&p + 1)); //&p是地址, + 1后还是地址,是地址就是4 / 8字节
//&p + 1,是p的地址+1,在内存中跳过p变量后的地址
printf("%d\n", sizeof(&p[0] + 1));//p[0]就是a,&p[0]就是a的地址,&p[0]+1就是b的地址,是地址就是4/8字节

printf("%d\n", strlen(p));//p中存放的是'a'的地址,strlen(p)就是从'a'的位置向后求字符串的长度,长度是6
printf("%d\n", strlen(p + 1));//p+1是'b'的地址,从b的位置开始求字符串长度是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));//p[0] -> *(p+0) -> *p ->'a',&p[0]就是首字符的地址,&p[0]+1就是第二个字符的地址
//从第2字符的位置向后数字符串,长度是5

1.3 二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));//数组名单独放在sizeof内部,计算的是整个数组的大小48
printf("%d\n",sizeof(a[0][0]));//4
printf("%d\n",sizeof(a[0]));//a[0]表示第一行的数组名,a[0]作为数组名单独放在sizeof内部,计算的是第一行的大小16
printf("%d\n",sizeof(a[0]+1));//a[0]作为第一行的数组名,没有&,没有单独放在sizeof内部,a[0]表示首元素地址,即a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,是地址就是4/8
printf("%d\n",sizeof(*(a[0]+1)));//第一行第二个元素,大小是4
printf("%d\n",sizeof(a+1));//a是二维数组的数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,即第一行的地址,a+1就是第二行的地址,是类型为int(*)[4]的数组指针,是地址就是4/8
printf("%d\n",sizeof(*(a+1)));//*(a+1)就是第二行,相当于第二行的数组名,*(a+1)->a[1],相当于计算第二行的大小,是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[1],相当于计算第二行的大小,是16字节
printf("%d\n",sizeof(*a));//a二维数组数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,即第一行的地址*a表示第一行a[0],大小是16字节
printf("%d\n",sizeof(a[3]));//感觉a[3]越界了,但是没关系,sizeof实际上算的是类型大小,大小是16字节

总结:
数组名的意义:

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

2. 指针笔试题

笔试题1:

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);
	printf( "%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}
//程序的结果是什么?

答案:2,5
解析:请添加图片描述

笔试题2

struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

答案:
0x100014 //要换成16进制
0x100001 //看清哦,这里没有*,数字加1就是加1
0x100004 //加unsigned int型指针,加4

笔试题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);
	return 0;
}

答案:4,200000(%x和%p都是打印地址,但%x不打印前面的0)
解析:((int)a + 1)中没有*,相当于整型+1跳过一个字节请添加图片描述

笔试题4

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

答案:1 //要看清楚{}里面的是(),括号表达式

笔试题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;
}

答案:FFFFFFFC,-4
解析:
请添加图片描述
请添加图片描述

笔试题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;
}

答案:at
解析:请添加图片描述

笔试题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请添加图片描述
第二次:* --*++cpp+3
先算++cpp再解引用,再–,解引用,再+3请添加图片描述
第三次: * cpp[-2]+3
相当于 * *(cpp-2)+3请添加图片描述
第四次:cpp[-1][-1]+1
相当于 * ( * (cpp-1)-1)+1请添加图片描述

这么多题,全部掌握了的话,你对指针和数组的了解就更上一层楼了。
就算现在还不明白,也不要放弃,随着之后的刷题和跟其他知识的融会贯通,遇到类似的题也可以回来看看这章博客,到时也能恍然大悟。
感兴趣的小伙伴可以关注我哦!一个赞一个评论一个收藏一个关注都是我不断写作的动力。

  • 35
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天影云光

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

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

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

打赏作者

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

抵扣说明:

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

余额充值