指针的一些笔试题
Posted 正义的伙伴啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指针的一些笔试题相关的知识,希望对你有一定的参考价值。
整型数组
int a[] = { 1,2,3,4 };//4*4=16
printf("%d\\n", sizeof(a));//16
printf("%d\\n", sizeof(a + 0));//4/8 a + 0 是第一个元素的地址,sizeof(a + 0)计算的是地址的大小
printf("%d\\n", sizeof(*a));//4 *a是数组的第一个元素,sizeof(*a)计算的是第一个元素的大小
printf("%d\\n", sizeof(a + 1));//4/8 a + 1是第二个元素的地址,sizeof(a+1)计算的地址的大小
printf("%d\\n", sizeof(a[1]));//4 - 计算的是第二个元素的大小
printf("%d\\n", sizeof(&a)); //4/8 - &a虽然数组的地址,但是也是地址,sizeof(&a)计算的是一个地址的大小
printf("%d\\n", sizeof(* &a));//16 - 计算的数组的大小
//&a -- int(*p)[4] = &a;
printf("%d\\n", sizeof(&a + 1));//4/8 - &a + 1 是数组后面的空间的地址
printf("%d\\n", sizeof(&a[0]));//4/8
printf("%d\\n", sizeof(&a[0] + 1));//4/8
数组名只有在两种情况下才代表整个数组:
- sizeof(数组名)------这里的数组名代表的是数组的地址,sizeof算的是整个数组的大小(这里注意括号里只有数组名时才表示数组的地址,例如sizeof(a+0)就不代表数组的地址了)
- &数组名------这里代表的是数组地址
sizeof后面放的参数无非就三种情况:
- 放的是只有单独一个数组名,这里结果时整个数组的大小(特殊情况)
- 放的是指针(除了上面的这种情况)返回的结果是4(32位操作系统)或 8(64位操作系统)
- 放的是变量,结果是返回变量类型的大小
字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\\n", strlen(arr));//随机值
printf("%d\\n", strlen(arr + 0));//随机值
//printf("%d\\n", strlen(*arr));//err
//printf("%d\\n", strlen(arr[1]));//err
printf("%d\\n", strlen(&arr));//随机值
printf("%d\\n", strlen(&arr + 1));//随机值-6
printf("%d\\n", strlen(&arr[0] + 1));//随机值-1
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
strlen函数传过去的是指针,返回值是’\\0’前面的所有字符个数。但是arr数组并没有’\\0’,顾strlen会访问越界直到遇到’\\0’为止,返回值也就是一个随机值。
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));//err
//printf("%d\\n", strlen(arr[1]));//err
printf("%d\\n", strlen(&arr));//6
printf("%d\\n", strlen(&arr + 1));//随机值
printf("%d\\n", strlen(&arr[0] + 1));//5
[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 char(*)[7]
printf("%d\\n", sizeof(&arr + 1));//4/8
printf("%d\\n", sizeof(&arr[0] + 1));//4/8
常量字符串
char* p = "abcdef";
printf("%d\\n", strlen(p)); //6
printf("%d\\n", strlen(p + 1));//5
printf("%d\\n", strlen(*p));//error
printf("%d\\n", strlen(p[0]));//error
printf("%d\\n", strlen(&p));//error &p是char **类型,传入参数应为char*类型
printf("%d\\n", strlen(&p + 1));//error
printf("%d\\n", strlen(&p[0] + 1)); //5
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
我们知道常量字符串是把首元素的地址存入指针中。
二维数组
int a[3][4] = { 0 };
printf("%d\\n", sizeof(a));//48 = 3*4*sizeof(int)
printf("%d\\n", sizeof(a[0][0]));//4 - a[0][0] - 是第一行第一个元素
printf("%d\\n", sizeof(a[0]));//16
printf("%d\\n", sizeof(a[0] + 1));//4 解释:a[0]作为数组名并没有单独放在sizeof内部,
//也没取地址,所以a[0]就是第一行第一个算的地址
//a[0]+1,就是第一行第二个元素的地址
printf("%d\\n", sizeof(*(a[0] + 1)));//4 - 解释:*(a[0] + 1)是第一行第二个元素
printf("%d\\n", sizeof(a + 1));//4 - 解释:a是二维数组的数组名,并没有取地址
//也没有单独放在sizeof内部,所以a就表示二维数组首元素的地址,即:第一行的地址
//a + 1就是二维数组第二行的地址
printf("%d\\n", sizeof(*(a + 1)));//16 解释:a+1是第二行的地址,所以*(a+1)表示第二行
//所以计算的就是第2行的大小
printf("%d\\n", sizeof(&a[0] + 1));//4 解释:a[0]是第一行的数组名,
//&a[0]取出的就是第一行的地址,&a[0]+1 就是第二行的地址
printf("%d\\n", sizeof(*(&a[0] + 1)));//&a[0]+1 就是第二行的地址
//*(&a[0]+1) 就是第二行,所以计算的第二行的地址
printf("%d\\n", sizeof(*a));//16 解释:a作为二维数组的数组名,没有&,没有单独放在sizeof内部
//a就是首元素的地址,即第一行的地址,所以*a就是第一行,计算的是第一行的大小
printf("%d\\n", sizeof(a[3]));//16 解释:a[3]其实是第四行的数组名(如果有的话)
//所以其实不存在,也能通过类型计算大小的
printf("%d\\n", sizeof(a[-1]));
这里再次解释一下二维数组的构造:
如果不是很了解的可以参考一下《关于指针的一些总结》——目录:数组指针
int a[3][4]={}; //实际上等价于
int *p[3]={a[0],a[1],a[2]};
a是代表首行数组的地址,由a[i]=*(a+i),可知a[i]实际上等于第i行数组的首元素的地址,而首元素的地址实际上相当于第i行数组的数组名,而a[i]作为数组名单独放在sizeof内结果是第i行的大小,整个二维数组实际上就相当于一个存放数组首元素指针的指针数组。
搞清楚了上面的关于指针的练习,我们来看几道笔试题:
笔试题一:
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
很明显&a是数组指针类型,它加一跳过整个数组
笔试题二:
//由结构体的内存对齐可知,该结构体的内存为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
printf("%p\\n", (unsigned long)p + 0x1); //2
printf("%p\\n", (unsigned int*)p + 0x1); //3
return 0;
}
这个笔试题实际上考察的是指针的类型的意义,指针类型决定指针的“步伐”有多大。
1 已知p是一个结构体指针,所以它加一内存会跳过20个字节,故结果为:0x10000014
2 指针p被强制类型转换为无符号长整型,整型加一,结果加一(注意这里已经不是指针了!)顾结果为:0x10000001.
3 指针p被强制类型转换为整型指针,顾加一内存会跳过4个字节,所以结果为:0x10000004
笔试题三:
#include<stdio.h>
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1); //1
int* ptr2 = (int*)((int)a + 1);//2
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
1 就不用多解释和前面的题一样
2 这里指针a被强制转换成int类型加一后又被强制转换成int类型指针。实际上指针a向后移动了一字节,而ptr2指向的内容是什么这就涉及到字节序——大小端存储,可以参考文章《数据在内存中的存储——具体在目录第二个》
笔试题四
#include<stdio.h>
#include<string>
int main()
{
int a[5][5];
int(*p)[4];
p =(int (*)[4]) a; //1
printf("%p,%d\\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
二维数组一直可以被看成一个指针数组(存放数组指针),//1实际上将a地址的值赋给了p,但p指针类型又是一个指向4个元素的指针数组,所以p每加一跳过一个四个元素的数组。整个a[5][5]实际上被重新划分了
从图中很直观的看出&p[4][2]和&a[4][2]之间差了四个元素,而指针-指针结果是之间元素的个数,所以答案是: FFFFFFFC -4
笔试题五:
#include <stdio.h>
int main()
{
const char* a[] = { "work","at","alibaba" };
const char** pa = a;
pa++;
printf("%s\\n", *pa);
return 0;
}
这里a是一个指针数组,数组存的是常量字符串第一个字符的地址。而a代表的 是首元素的地址,故为一个二级指针。pa++指向了数组的下个元素也就是常量字符串“at”首元素地址的地址,顾打印的结果为at
笔试题六:
#include<stdio.h>
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
}
和笔试题五一样我们知道指针c是一个char **类型存放的是常量字符串首字符的地址的地址。
两个数组的结构如下图:
一
printf("%s\\n", **++cpp);
指针先自增再两次解引用,最后得到的是p3的地址,顾打印结果为: POINT
二
printf("%s\\n", *-- * ++cpp + 3);
指针cpp先自增再解引用再自减再解引用得到p1,p1+3指向的是E的地址,所以字符串从‘E’开始打印,最后结果为:ER
三
printf("%s\\n", *cpp[-2] + 3);
cpp[-2]等价于*(cpp-2),顾表达式也可以写成 * *(cpp-2)+3,和上面一样可以得到指向‘S’的指针,结果为:ST
四
printf("%s\\n", cpp[-1][-1] + 1);
cpp[-1][-1]等价于*(*(cpp-1)-1),思路和上面一样,结果为:EW
总结:
关于指针我们一定要注意的是一定要搞清楚指针的类型,因为指针的类型决定了指针的定义还决定了指针加减整数,其次要搞清楚指针的指向。弄清楚这两点指针的题就可以迎刃而解了。
以上是关于指针的一些笔试题的主要内容,如果未能解决你的问题,请参考以下文章