C语言——指针面试题详解

🐒个人主页:平凡的小苏
📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情

目录

 1. 指针和数组笔试题解析

 一维数组

字符数组

二维数组

2. 指针笔试题

笔试题1:

笔试题2:

笔试题3

 笔试题4

 笔试题5

笔试题6  

笔试题7

笔试题8


 1. 指针和数组笔试题解析

数组名的意义:

1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

3. 除此之外所有的数组名都表示首元素的地址

 一维数组

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
//这里数组名单独放在sizeof内部,计算整个数组的大小,结果为16
printf("%d\n",sizeof(a+0));
//这里数组名没有单独放在sizeof内部,是数组首元素的地址,结果为4/8
printf("%d\n",sizeof(*a));
//这里数组首元素的地址解引用,计算的是元素大小,结果为4
printf("%d\n",sizeof(a+1));
//这里数组首元素地址加1,也是地址,是地址结果就是4/8
printf("%d\n",sizeof(a[1]));
//这里计算元素大小,结果为4
printf("%d\n",sizeof(&a));
//取出整个数组的地址,是地址结果就为4/8
printf("%d\n",sizeof(*&a));
//取出数组的地址,然后解引用,本质是数组名单独放在sizeof内部,结果为16
printf("%d\n",sizeof(&a+1));
//地址加1,是地址结果就为4/8
printf("%d\n",sizeof(&a[0]));
//取出首元素的地址,是地址结果就为4/8
printf("%d\n",sizeof(&a[0]+1));
//结果为4/8

字符数组

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
//数组名单独,结果为6,因为sizeof计算的是占用内存的大小,不用找\0,并且看类型
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));
//取出首元素地址加1,跳过四个字节,是地址结果为4/8



printf("%d\n", strlen(arr));
//strlen是遇到'\0'停止,这个不知道什么时候遇到'\0',所以结果为随机值
printf("%d\n", strlen(arr+0));
//同上为随机值
printf("%d\n", strlen(*arr));
//对arr解引用拿到第一个字符,转为十进制为97,strlen是用地址一个一个访问的,所以这个代码error
printf("%d\n", strlen(arr[1]));
//同上error
printf("%d\n", strlen(&arr));
//随机值
printf("%d\n", strlen(&arr+1));
//随机值
printf("%d\n", strlen(&arr[0]+1));
//随机值
char arr[] = "abcdef";
//“abcdef\0”数组长度为7
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));
//取出数组的地址加1,跳过数组,指向数组后边,但也是地址,是地址结果就为4/8
printf("%d\n", sizeof(&arr[0]+1));
//是地址结果就为4/8


printf("%d\n", strlen(arr));
//strlen遇到斜杠0就停止,结果为6
printf("%d\n", strlen(arr+0));
//同上,结果为6
printf("%d\n", strlen(*arr));
//解引用拿到的是字符a,代码错误
printf("%d\n", strlen(arr[1]));
//同上,代码错误
printf("%d\n", strlen(&arr));
//取出数组的地址,但是数组地址开始也是指向首元素的地址,所以结果为6
printf("%d\n", strlen(&arr+1));
//取出数组的地址加1,跳过整个数组,然后不知道什么时候遇到斜杠0,所以为随机值
printf("%d\n", strlen(&arr[0]+1));
//取出数组首元素地址加1,跳过一个字节,结果为5
char *p = "abcdef";
printf("%d\n", sizeof(p));
//该指针变量存放的是该字符串首字符的地址,是地址结果就为4/8
printf("%d\n", sizeof(p+1));
//是地址结果就为4/8
printf("%d\n", sizeof(*p));
//对指针p解引用,计算的是该字符元素的大小,结果为1
printf("%d\n", sizeof(p[0]));
//同上,结果为1
printf("%d\n", sizeof(&p));
//是地址,结果就为4/8
printf("%d\n", sizeof(&p+1));
//是地址,结果就为4/8
printf("%d\n", sizeof(&p[0]+1));
同上,结果为4/8;

printf("%d\n", strlen(p));
//strlen遇到'\0'就停止,结果为6
printf("%d\n", strlen(p+1));
//p+1跳过一个字节,结果为5
printf("%d\n", strlen(*p));
//拿到的是字符a,转为ascii吗为97,该代码错误
printf("%d\n", strlen(p[0]));
//同上,该代码错误
printf("%d\n", strlen(&p));
//取p的地址,不知道什么时候遇到斜杠0,所以为随机值
printf("%d\n", strlen(&p+1));
同上,结果为随机值
printf("%d\n", strlen(&p[0]+1));
取首字符的地址+1跳过一个字节,计算的结果为5

二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));
//结果为48,3*4*4=48
printf("%d\n",sizeof(a[0][0]));
//计算元素的大小结果为4
printf("%d\n",sizeof(a[0]));
//a[0]是第一行一维数组的数组名,数组名单独放在sizeof内部,计算的是第一行数组的大小,结果为16
printf("%d\n",sizeof(a[0]+1));
//没有单独放在sizeof内部,是数组的首元素,+1跳过四个字节,指向第一行第二列的地址,是地址就为4/8
printf("%d\n",sizeof(*(a[0]+1)));
//计算的是元素的大小结果为4
printf("%d\n",sizeof(a+1));
//a没有单独放在sizeof内部,是首元素的地址,是第一行的地址,+1指向第二行的地址,是地址就为4/8
printf("%d\n",sizeof(*(a+1)));
a没有单独放在sizeof内部,是首元素的地址,是第一行的地址,+1指向第二行的地址,进行解引用得到第二行的数组名,计算的是第二行数组的大小结果为16
printf("%d\n",sizeof(&a[0]+1));
取出第一行的地址,再+1指向第二行的地址,是地址就为4/8
printf("%d\n",sizeof(*(&a[0]+1)));
取出第一行的地址,再+1指向第二行的地址,再进行解引用,得到第二行的数组名,计算的是第二行数组的大小,结果为16
printf("%d\n",sizeof(*a));
a是二维数组的数组名,没有单独放sizeof内部,是一维数组第一行的地址,然后进行解引用,得到第一行的数组名,计算的是第一行数组的大小,结果为16
printf("%d\n",sizeof(a[3]));
//第四行的数组名,虽然越界了但是知道了列,就知道一行有多少个元素,因为sizeof是看类型计算的大小,sizeof再编译阶段就完成了计算,越界不影响,所以结果为16

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
解释:1.a是数组名,为数组首元素的地址,加1跳过4个字节,在进行解引用就得到了2
2.取出数组的地址再进行+1,跳过整个数组,因为取出数组的地址是数组指针类型,想要放在ptr里面,就需要强制类型转换。ptr-1往回跳一个字节再进行解引用得到的结果为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);
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);
 return 0;
}
结果为:00100014,00100001,00100004
解释:1.因为结构体的大小为20个字节,指针p+1跳过20个字节所以结果为00100014
2.先将p强制类型转换为无符号整型,整型+1就跳过一个字节,所以地址为00100001
3.将p强制类型转换为无符号整型指针,无符号整型指针+1就跳过四个字节,所以地址为00100004

笔试题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,2000000

解释如图所示:

 笔试题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
解释:因为该数组里面的括号为逗号表达式,所以数组的元素为1 3 5 0 0 0
p[0]访问的是a[0][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;
}
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;
}

 

 解释:&p[4][2]-&a[4][2]两个指针相减得到的是-4,又因为-4放入内存是补码

则-4的补码为:11111111111111111111111111111100,所以它的地址为fffffc。用%p打印出来就是fffffc

而用%d打印就是-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
解释:1.取出二维数组的地址+1,跳过整个二维数组,强制类型转换为int*,放入ptr1,然后ptr-1再进行解引用得到的就是10
2.aa是数组名,是一维数组的数组名,是第一行数组的地址,aa+1跳过一行得到第二行的地址解引用,强制类型转换为int*放入ptr2,ptr2-1再进行解引用打印出来的就是5

笔试题7

#include <stdio.h>
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\n", *pa);
 return 0;
}
结果为:at
解释:a数组每个元素的类型为char*,所以需要二级指针来接收数组a的地址,然后pa++,跳过一个字节,所以pa指向了a首字符的地址,再对pa进行解引用找到了字符a利用%s打印出来就是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存放的是cp首元素的地址,cp 存放的是c的地址

1.由操作符优先级可知,先进行++cpp,所以cpp指向了c+2,然后对cpp第一次解引用得到了c+2的地址,再进行解引用找到了POINT首字符的地址,所以打印出来的是POINT

2.由于cpp已经指向了c+2,所在进行++cpp,就又指向了c+1,对他进行解引用找到了c+1的地址再进行--,所以c+1变为了(c+1-1)得到c,再进行解引用找到了ENTER首字符的地址,再进行+3,跳过三个字节,所以打印出来的是ER

3.由于cpp已经指向了c+1,而那个c+1地址又已经变为了c的地址,所以cpp[-2]本质为*(cpp-2)找到了c+3的地址再进行解引用得到了FIRST首字符的地址,再进行+3跳过了三个字节,所以打印出来的是ST

4.由于cpp已经指向了c+1,而那个c+1地址又已经变为了c的地址,所以cpp[-1][-1]本质为

*(*(cpp-1)-1)找到了NEW首字符的地址,再进行+1跳过一个字节,所以打印出EW

小编的分享到这里就结束了!如果有什么不足的地方,请大佬们指点,小编一定吸取教训,将文章质量提高!!! 

  • 47
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

平凡的小苏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值