C语言-八道题深入理解c指针

Posted 4nc414g0n

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言-八道题深入理解c指针相关的知识,希望对你有一定的参考价值。

八道题深入理解c指针

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
解释:
&a + 1,由于&与数组名结合&a表示整个数组&a + 1指向数组尾
由于&a+1的类型是int*[5]所以类型转换为int*
由于ptr为int*, ptr - 1即向前4个字节指向元素5

2. 第二题

  • 假设p 的值为0x100000。 如下表表达式的值分别为多少?
struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;

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

分别是0x100014,0x100001,0x100004
解释:

  1. 0x1就是16进制的1,p指向的结构体的大小是20个字节,p+1即0x100000加16进制的20及0x100014
  2. (unsigned long)p,强转为unsigned long后加0x1就看作十进制加1即为0x100001
  3. (unsigned int*)p,强转为unsigned int*后加0x1就是跳过一个无符号整形变量即加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;
}

在这里插入图片描述

打印 4,2000000
解释:

  1. ptr1参考题一
  2. ptr2: a指向第一个元素被强转为int后如图绿色部分之后在被强转为int*赋给ptr2,并且一个字节一个地址,也就是0x0012ff44和0x0012ff45差一个字节
  3. 打印时按照%x打印,从高地址处取ptr2为0x02000000
    ptr1[-1] == *(ptr1-1),ptr1为0x00000004
    而%x只会从有效数字开始打印,即打印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
解释:注意!!!: a[3][2]花括号内是三个逗号表达式,相当于a[3][2]={1,3,5};

  1. 此二维数组相当于{{1,3},{5,0},{0,0}}
  2. 未与sizeof或&结合,a[0]为二维数组的首元素也就是第一行数组的数组名,也就是第一行数组首元素1的地址
  3. p[0] == *(p+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;
}

在这里插入图片描述

结果为FFFFFFFC,-4
解释:

  1. p类型为int(*)[4],而a第一行是五个整形的数组,作为地址类型应该是int(*)[5],p+1只能向后访问4个元素,而a+1可以访问5个
  2. p[4] == *(p+4)即图中p+4向后取4个元素,&p[4][2]表示第五行第三个元素地址,如图,&p[4][2] - &a[4][2]表示相差元素个数由于&p[4][2]地址比&a[4][2]地址小,为-4
  3. -4原码1000000000000000000000000000100
    反码:11111111111111111111111111111111011
    补码:11111111111111111111111111111111100
    按照%p格式打印就将补码看作地址:FFFFFFFC
    按照%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. ptr1指向二维数组尾部
  2. *(aa+1) == aa[1],指向元素6, 本来就是(int*)类型
  3. 即*(ptr1 - 1),和*(ptr2 - 1)都是打印向前一个字节的元素

7. 第七题

  • 程序运行结果是什么?
#include <stdio.h>
int main()
{
 char* a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\\n", *pa);
 return 0;
}

在这里插入图片描述

结果是 at
解释:

  1. char* a[] = {“work”,“at”,“alibaba”},代表一个数组每个元素是char*分别存放的是后面字符串首字母的地址
  2. pa存放char*地址,应为二级指针。pa++指向a数组第二个元素,即打印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
解释:

  1. 第一次如图所示++cpp再**解引用两次打印POINT
  2. 第二次cpp在第一次的基础上++指向c+1,*解引用指向c数组的第二个元素,再–1,cp中第三个元素由c+1变为c,指向c数组的第一个元素,最后+3即打印ER
  3. 第三次cpp[-2] == *(cpp-2),再*解引用最后+3 打印ST
  4. 第四次cpp[-1][-1] == *(*(cpp-1)-1),先指向cp数组中的c+2再-1后变为c+1再解引用,最后+1打印EW

以上是关于C语言-八道题深入理解c指针的主要内容,如果未能解决你的问题,请参考以下文章

深入理解C语言的指针

C语言之深入解析如何理解指针和结构体指针指针函数函数指针

C语言的罗盘——指针!深入理解C语言指针及其应用

C语言 二重指针深入理解

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针