指针知多少(指针进阶习题讲解:指针篇)

指针知多少(指针进阶习题讲解:指针篇),第1张

指针知多少(指针进阶习题讲解:指针篇)

上一篇的题目不知感觉如何,感觉良好的话,就进入下面的内容

注:这次的题目会更难

那就开始吧

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后解引用就是a[1]

&a是取出整个数组的地址,+1后便来到数组末尾,如图:

所以ptr指向数组末尾

故ptr-1后来到a[4]的起始位置

解引用后结果为5

输出结果为2  5

 

2.

struct Test
{
    int Num;
    char *pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;

//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节

int main()
{
    printf("%pn", p + 0x1);
    printf("%pn", (unsigned long)p + 0x1);
    printf("%pn", (unsigned int*)p + 0x1);
    return 0;
}

这题考查指针+1后是增加多少个字节

p+0x1,因为p是指针,结构体大小为20,所以p+1是加20个字节,换成十六进制就是14

结果就是0x100014

将p强制转换成unsigned long后,+1就是数学上的+1计算了,结果是0x100001

p强制转换成unsigned int*,int是4个字节,+1就是加4个字节,结果是0x100004

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

这题比较复杂

&a+1是数组末尾,ptr[-1]等效于*(ptr-1),结果是4

(int)a+1,因为a的类型被强制转换,所以+1就是数学上的a+1,转换成int*后来到a[0]的第二个字节,这里涉及到大小端的问题,假设是小端存储,ptr2取到的4个字节如下:

将其转换成十六进制结果就是2000000

  

4.

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

这题不复杂,结果如下

5.

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

数组a是5行5列的二维数组,p是数组指针,但p指向的数组一列只能有4个元素,所以&p[4][2]和&a[4][2]的位置是不同的

 指针和指针相减,结果为二者之间的相隔的元素的个数,因为是小地址减大地址,所以是-4

第二个值就是-4

第一个值因为是以%p的形式打印,地址是不会有负数的,所以打印的是-4的补码,以十六进制的形式打印,结果是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;
}

&aa+1是数组末尾地址,-1后是数组最后一个元素地址,结果是10

aa+1是aa[1]的首地址,-1后是aa[0][4]的地址,结果是5

7.

int main()
{
	char* a[] = { "work","at","home" };
	char** pa = a;
	pa++;
	printf("%sn", *pa);
	return 0;
}

 pa存储的是数组首元素的地址,++后指向第二个元素,结果是"at"

8.

int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%sn", **++cpp);
	printf("%sn", *-- * ++cpp + 3);
	printf("%sn", *cpp[-2] + 3);
	printf("%sn", cpp[-1][-1] + 1);
	return 0;
}

 这一题一定要把他们之间的关系理清,否则你做不出来

初始指向关系如下:

  

**++cpp:前置++优先级高于*,所以cpp先进行++,++后指向c+2然后解引用来到数组c中第三个char*,内容为字符串"POINT"的首地址,再次解引用就是字符串“POINT”

 *-- * ++cpp + 3:经过**++cpp后,cpp指向c+2,如图:

这里 *** 作符先后顺序要清楚,前缀++优先级高于+,所以先算++,来到c+1的位置,然后进行解引用得数组c中的c[1],*--c[1]+3,之后算--得c[0],*c[0]+3,解引用c[0]来到字符串“ENTER”首字符的位置,+3后是字符“E”的位置,所以结果是"ER"

*cpp[-2] + 3:上述两步 *** 作后cpp在c+1的位置

*cpp[-2]就是*(cpp-2) ,cpp-2来到c+3位置,解引用后是数组c中第四个char*,内容为字符串“FIRST”首字符地址,+3后是字符“S”的位置,结果是“ST”

printf("%sn", cpp[-1][-1] + 1):上一步中没有++和-- *** 作,所以cpp位置不变,cpp[-1][-1]等效于*(*(cpp-1)-1),cpp-1来到c+2位置,解引用后数组c第三个char*,再次-1后是第二个char*位置,再次解引用来到字符串“NEW”首字符位置,+1后便是字符“E”的位置,所以结果是“EW”

结果如下图:

指针的习题到这就结束了,关于指针进阶的内容也基本上结束了,关于C语言的内容后面会继续更新

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5710528.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存