指针笔试题(帮助你全面理解指针!!!)

目录

笔试题1:

笔试题2:

笔试题3:

笔试题4:

笔试题5:

笔试题6:

笔试题7:


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

程序的结果是什么呢?

首先我们来运行一下程序:

指针笔试题(帮助你全面理解指针!!!)_第1张图片

则答案为    2     5

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第2张图片

&a-------int(*)[5](类型),如果要将&a赋值给p,则有int (*p)[5] = &a

&a是数组的地址,&a+1跳过整个数组

&a+1强制类型转换为和指针变量ptr相同的类型,ptr-1表示减去一个整型的地址

*(a+1)a是数组名,表示首元素地址,a的类型为(int*),如图a位置,加1表示跳过一个元素,指向2的位置,如图a+1,解引用后值为2。

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

程序的结果是什么呢?

运行代码:

指针笔试题(帮助你全面理解指针!!!)_第3张图片

 则答案为    00100014    00100001    00100004

详细分析:

p+0x1:表示p+1,指针加1(取决于指针类型——结构体指针),此结构体类型的大小为20个字节,所以增加20,而地址的表示方法是16进制,20的16进制为14,最终结果为00100014。

(unsigned long)p+0x1:p是一个结构体指针类型,将结构体指针类型强制类型转换为unsigned long类型,整形加1就是加1,结果为00100001。

(unsigned int*)p+0x1:将结构体指针类型强制类型转换为unsigned int*类型,整形指针+1,跳过4个字节,最终结果为00100014。

笔试题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张图片

则答案为    4    2000000

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第5张图片

%p --------- 是打印地址

%x --------- 是16进制的格式打印

&a+1:增加一个数组a的大小;将其转化为int*类型在赋给指针变量ptr1。如图所示

(int)a + 1:a是一个数组名,表示首元素地址,首元素的地址强制类型转换为整形,整形加一就是加一,跳过一个字节;将其转化为int*类型在赋给指针变量ptr2。

ptr1[-1] ------->  *(ptr1-1)

ptr1为一个整型指针,整形指针减一,即向前移一个整型,如图所示 ptr1-1,解引用向后访问四个字节(04  00  00  00),即为4

ptr2为一个整型指针,解引用向后访问4个字节,如图所示(00  00  00  02),假设是小端放入,还原回来就是(02  00  00  00),16进制打印出来就是0x2000000

笔试题4:

#include 
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

程序的结果是什么呢?

运行代码:

指针笔试题(帮助你全面理解指针!!!)_第6张图片

则答案为    1

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第7张图片

区别于:int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };

原题为逗号隔开的表达式,表达式结果为:int a[3][2] = { 1, 3, 5 };

a[0]:第一行的数组名,没有单独放入sizeof内部,数组名表示首元素地址。相当于&a[0][0]

p[0]  --------->  *(p+0)

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

程序的结果是什么呢?

运行代码:

指针笔试题(帮助你全面理解指针!!!)_第8张图片

则答案为    FFFFFFFC   -4

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第9张图片

int (*p)[4]:p为一个指针,指向一个数组,是四个元素,每个元素是整形

把a赋值给p,a是一个数组名(表示首元素的地址),即二维数组的第一行地址

a--------->int (*)[5]类型      p------->int (*)[4]类型

p+1:跳过4个整形

p[4][2] ----------->  *(*(p+4)+2):对于p+4(数组指针)解引用有权利会访问到4个整形元素

&p[4][2] - &a[4][2]:指针和指针相减得到的是指针之间的元素个数,小地址减大地址(负数),得到-4,

-4:以%d打印就是 -4,以%p(地址)打印就是 FFFFFFFC 如图所示(内存以补码的形式存储)

笔试题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张图片

则答案为    10    5

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第11张图片

二维数组的本质是一维数组,比如此题的数组aa表示数组内含有两个元素,分别是两个一位数组,

而这两个一维数组又分别包含五个元素。

&aa+1:aa表示整个数组的地址,加1为跳过整个数组。

*(aa+1):aa为数组首元素的地址(第一行的地址),加1(第二行地址),解引用得到第二行(*(aa+1) ---------> aa[1]----第二行的数组名没有单独放入sizeof内部,也没有取地址,表示首元素地址,即&aa[1][0])

 ptr1和ptr2都为指针,指针减整型,减去存储内存的元素的类型。

ptr1-1:向前移动一个整型指针,解引用得到10

ptr2-1:向前移动一个整型指针,解引用得到5

笔试题7:

#include 
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

程序的结果是什么呢?

运行代码:

指针笔试题(帮助你全面理解指针!!!)_第12张图片

则答案为    at

详细分析:

指针笔试题(帮助你全面理解指针!!!)_第13张图片

char* a[]为指针数组,是数组用来存放指针,该数组有三个元素,分别是三个字符串的地址。

pa = a:是将数组a的首元素的地址放入二级指针变量pa中。

pa++:跳过一个char*的元素

*pa:此时pa为a[1],也就是第二个元素表示字符串的首地址,以%s的形式输出,依次打印字符串。

你可能感兴趣的:(C语言,c++,数据结构,c语言,学习)