目录
本篇博文,将从指针和数组来为大家分析一些笔试题,设计内容多,全是干货,接下来让我们一起来看一下吧
数组笔试题
在做题之前,我们需要明白
数组名是数组首元素的地址 | ||
但是有2个例外: | ||
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节 | ||
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址 |
一维数组
我们首先看题,答案再代码后面
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));// 16
printf("%d\n",sizeof(a+0));// 4/8
printf("%d\n",sizeof(*a));// 4
printf("%d\n",sizeof(a+1));// 4/8
printf("%d\n",sizeof(a[1]));// 4
printf("%d\n",sizeof(&a));// 4/8
printf("%d\n",sizeof(*&a));// 16
printf("%d\n",sizeof(&a+1));// 4/8
printf("%d\n",sizeof(&a[0]));// 4/8
printf("%d\n",sizeof(&a[0]+1));// 4/8
接下来博主会为大家一句一句进行解释
printf("%d\n",sizeof(a));// 16
解释:sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,所以是16
printf("%d\n",sizeof(a+0));// 4/8
解释:这里的sizeof没有和a直接相连,所以这里并不是整个数组,这里a代表数组首元素的地址,a+0依然是首元素的地址,既然是地址,所以大小为4或8,具体大小由编译器决定
printf("%d\n",sizeof(*a));// 4
解释:*a是数组的首元素,且为int型,所以大小为4
printf("%d\n",sizeof(a+1));// 4/8
解释:a为首元素的地址,a+1为第二个元素的地址,所以大小为4或8
printf("%d\n",sizeof(a[1]));// 4
解释:a[1]为第二个元素,大小为8
printf("%d\n",sizeof(&a));// 4/8
解释:&a为地址,所以大小为4或8
printf("%d\n",sizeof(*&a));// 16
解释:&a是a的地址,前面加上解引用*,则*&a就为a,所以大小为16
printf("%d\n",sizeof(&a+1));// 4/8
解释:&a是地址,那么&a+1也还是地址,所以大小为4或8
printf("%d\n",sizeof(&a[0]));// 4/8
解释:&a[0]是首元素地址,既然是地址,所以大小为4或8
printf("%d\n",sizeof(&a[0]+1));// 4/8
解释:&a[0]为地址,那么&a[0]+1也是地址,既然是地址,所以大小为4或8
字符数组
题 一
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));// 6
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", sizeof(arr));// 6
解释:数组名单独放在sizeof内部,这里的arr表示整个数组,计算的是整个数组的大小,单位是字节,总共6个字节
printf("%d\n", sizeof(arr+0));// 4/8
解释:arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));// 1
解释:arr表示数组首元素的地址,*arr就是首元素,大小1个字节
printf("%d\n", sizeof(arr[1]));// 1
解释:arr[1]就是第二个元素,大小是1个字节
printf("%d\n", sizeof(&arr));
解释:&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8
printf("%d\n", sizeof(&arr + 1));
解释:&arr + 1是跳过整个数组后的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
解释:第二个元素的地址,是4/8个字节
题 二
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机值
printf("%d\n", strlen(arr + 0));//arr
printf("%d\n", strlen(*arr));//err
printf("%d\n", strlen(arr[1]));//err
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
在讲解提二是我们需要了解以下strlen这个函数
格式为
还需要了解一下这个arr的存储
明白这些后,我们开始解释代码
printf("%d\n", strlen(arr));
解释:因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值
printf("%d\n", strlen(arr + 0));
解释:arr + 0是首元素的地址,和第一个一样,也是随机值
printf("%d\n", strlen(*arr));//err,
解释: arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97,strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参,strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了,如果访问就会出现下面的情况
printf("%d\n", strlen(arr[1]));//err
解释:与上一条同理
printf("%d\n", strlen(&arr));//随机值
解释:&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计直到/0结束
printf("%d\n", strlen(&arr + 1));//随机值
解释:与&arr类似,&arr+1是数组的地址加一,所以也是随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
解释:&arr[0] + 1是第二个元素的地址。结果也是随机值
题 三
char arr[] = "abcdef";//[a b c d e f \0]
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
我们先看一下arr里面都有什么吧
解释如下
printf("%d\n", sizeof(arr));//7
解释:arr中存储了7个char型色元素,所以为7
printf("%d\n", sizeof(arr + 0));// 4/8
解释:arr + 0是首元素的地址,是地址,所以为4/8
printf("%d\n", sizeof(*arr));// 1
解释:*arr其实就是首元素,1个字节。等价关系:*arr--> *(arr+0) -- arr[0]
printf("%d\n", sizeof(arr[1]));// 1
解释:arr[1]是第二个元素,1个字节
printf("%d\n", sizeof(&arr));// 4/8
解释:&arr是数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr + 1));// 4/8
解释:&arr + 1是跳过一个数组的地址,是地址,所以为4/8
printf("%d\n", sizeof(&arr[0] + 1));// 4/8
解释:&arr[0] + 1是第二个元素的地址,是地址,所以4/8
题 四
// char arr[] = "abcdef";//[a b c d e f \0]
// printf("%d\n", strlen(arr));//6
// printf("%d\n", strlen(arr + 0));//6
// printf("%d\n", strlen(*arr));//*arr为首元素,所以这里错误,err
// printf("%d\n", strlen(arr[1]));//arr[1]为第二个元素,所以这里也错误
// printf("%d\n", strlen(&arr));//6
// printf("%d\n", strlen(&arr + 1));//随机值
// printf("%d\n", strlen(&arr[0] + 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));// 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", sizeof(p));// 4/8
解释:p是一个指针变量,指针大小为4/8
printf("%d\n", sizeof(p + 1));// 4/8
解释:p+1是'b'的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(*p));// 1
解释:*p 就是'a',就是1个字节
printf("%d\n", sizeof(p[0]));// 1
解释:p[0]等价 *(p+0)等 价 *p ,所以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
解释:都为地址,所以大小都为4/8个字节
题 六
// char* p = "abcdef";
// printf("%d\n", strlen(p));//6
// printf("%d\n", strlen(p + 1));//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));//5
这题我就不详细讲解了,请各位宝子们配合下图与前面所讲自行理解一下吧
二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));// 48
printf("%d\n",sizeof(a[0][0]));// 4
printf("%d\n",sizeof(a[0])); // 16
printf("%d\n",sizeof(a[0]+1));// 4/8
printf("%d\n",sizeof(*(a[0]+1)));// 4
printf("%d\n",sizeof(a+1));// 4/8
printf("%d\n",sizeof(*(a+1)));// 16
printf("%d\n",sizeof(&a[0]+1));// 4/8
printf("%d\n",sizeof(*(&a[0]+1)));// 16
printf("%d\n",sizeof(*a));// 16
printf("%d\n",sizeof(a[3]));// 16
在做题之前,务必知道下图中的知识点
二维数组可以看成存放着一维数组的数组 ,接下来我们看一下题解
printf("%d\n", sizeof(a));// 48
解释:3*4*4 = 48
printf("%d\n", sizeof(a[0][0]));//4
解释:首元素a[0][0]的大小
printf("%d\n", sizeof(a[0]));// 16
解释:a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
printf("%d\n", sizeof(a[0] + 1));// 4/8
解释:a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&。a[0]表示数组首元素的地址,也就是a[0][0]的地址。所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));//4
解释:计算的是就是第一行第2个元素的大小
printf("%d\n", sizeof(a + 1));// 4/8
解释:a是数组首元素的地址,是第一行的地址 int(*)[4]。a+1 就是第二行的地址
printf("%d\n", sizeof(*(a + 1)));// 16
解释:*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小。a+1 --> 是第二行的地址,int(*)[4]。*(a+1) 访问的第二行的数组
printf("%d\n", sizeof(&a[0] + 1));// 4/8
解释:&a[0]是第一行的地址 int(*)[4],&a[0]+1 是第二行的地址 int(*)[4]
printf("%d\n", sizeof(*(&a[0] + 1)));// 16
解释:计算的是第二行的大小
printf("%d\n", sizeof(*a));// 16
解释:计算的是第一行的大小-16。a是数组首元素的地址,就是第一行的地址。*a 就是第一行,*a 等价于*(a+0) 等价于 a[0]
printf("%d\n", sizeof(a[3]));// 16
解释:a[3]等价于int [4],所以大小为16
指针笔试题
笔试题一
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;
}
解释图如下
笔试题二
//这里告知结构体的大小是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;
}
这里我们注意我们如果要运行这个代码,并得出题中所要求的结果,我们还需要对*p进行改造,如下
//struct Test
//{
// int Num;
// char* pcName;
// short sDate;
// char cha[2];
// short sBa[4];
//}* p = (struct Test*)0x100000;
这样p就等于0x100000,就可以开始运行测试了,运行结果如下
这道题我们来一句一句解读一下
printf("%p\n", p + 0x1);
解释:p为指针变量,加0x1就就是加一,也就是跳过一个结构体(20个字节),所以结果为0x100014
printf("%p\n", (unsigned long)p + 0x1);
解释:这里由于强制类型转换了为unsigned long型,所以这里的加0x1就是加1,所以结果为0x100001
printf("%p\n", (unsigned int*)p + 0x1);
解释:这里由于强制类型转换了为unsigned int*型,这里加一就只跳了一个整型的,所以加4,结果为0x100004
笔试题三
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;
}
首先我们得明白这个数组在内存中如何存储,如下图所示
其次我们得知道&a,&a+1,int(a),int(a)+1,以及ptr[-1]与ptr的位置,如下图
最后我们还得知道需要访问几个字节,因为打印用的%x,所以访问四个字节
所以最后结果为00000004和00000002
笔试题四
#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;
}
这道题,需要我们注意的是,数组中的元素,(0,1)其实表示的是一个元素为1,这是一个逗号表达式,后面就可以依次类推,结果如下图所示
则p[0]就等价于a[0][0],所以结果为1
笔试题五
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;
}
这里我借一位大牛的图来跟大家讲解一下
则由图所知&p[4][2]-&a[4][2]的大小为-4,如果用%p打印的话,打印的就是-4的补码,转换如下
// //10000000000000000000000000000100---原码
// //11111111111111111111111111111011---反码
// //1111 1111 1111 1111 1111 1111 1111 1100---补码
// //F F F F F F F C
所以结果为
笔试题六
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
笔试题七
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
这道题我们得明白,a是一个指针数组,a里面每一个字符串都是一个指针
那么这道题就简单了,
则*pa就就是字符串"work"的地址,所以结果就为work
总结
至此,指针进阶部分就讲解完了,有不对或者不懂的地方记得评论去留言或私信博主!!!
博主制作不易,记得三连。以便关注博主后续创作!!!