C语言——指针练习,逐步解析

一、程序求解

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 表示数组后面的空间的地址,类型为int(*)[5]即指向长度为 5 的数组的指针
  • 然后强制类型转换为int(*)类型即整型指针

对第一个问题*(a+1)

a 为数组首元素地址,a+1 为数组第二个元素的地址,解引用后表示数组第二个元素即 2

对第二个问题*(ptr - 1)

ptr-1 为数组第五个元素的地址,解引用后表示第五个元素即 5

二、程序求解

指针类型决定了指针走一步有多大

//假设p为0x100000
//已知,Test 类型的结构体变量大小是 20 个字节
struct Test
{
    int Num;
    char* pcName;
    short 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,0x1000001,0x1000004

对第一个问题p + 0x1

由已知得,结构指针变量 p 加1就是加一个结构体指针的大小即 20

对第二个问题(unsigned long)p + 0x1

强制类型转换成整型类型,加 1 就是加 1

对第三个问题(unsigned int*)p + 0x1

强制类型转换成整型指针类型,加 1 就是加 4

三、程序求解

int main()
{
    int a[4] = { 1,2,3,4 };
    int* ptr1 = (int*)(&a + 1);
    int* ptr2 = (int*)((int)a + 1);
    printf("%x,%x\n", ptr1[-1], *ptr2);
    return 0;
}

解析:4,2000000

对整形指针 ptr1:

  • &a+1就是数组后面的空间的地址,类型为int(*)[4]即指向长度为 4 的数组的指针
  • 然后强制类型转换为int(*)类型即整型指针

对整形指针 ptr2:

  • (int)a 表示数组名 a 即首元素的地址被强制类型转换为int
  • 然后 +1 就是加1,即地址加了1,在内存上就是加 1byte
  • 最后强制类型转换为int*
  • 总的来说就是,数组的首元素地址向后偏移了 1byte,类型为int*(整型指针 +1 就是跨4字节,这里是转换成整型变量+1)

对第一个问题ptr1[-1]

ptr1[-1] == *(ptr1+(-1)) == *(ptr1-1),见下图

对第二个问题*ptr2

见下图

在这里插入图片描述

在这里插入图片描述

四、程序求解

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

  • p 的类型为int(*)[4]

  • a(即二维数组数组名)表示第一行的地址,类型为int (*)[5]

  • p[4][2]可以看作*(*(p+4)+2)

对第二个问题&p[4][2] - &a[4][2]:

差值为 -4

对第一个问题&p[4][2] - &a[4][2]:

就是在内存中 -4 的写法,即 -4 的补码,打印出来就是 FFFFFFFC

在这里插入图片描述

在这里插入图片描述

五、程序求解

int main()
{
    int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
    int* ptr1 = (int*)(&arr + 1);
    int* ptr2 = (int*)(*(arr + 1));
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    return 0;
}

解析:10,5

对整型指针变量 ptr1:

  • &arr+1就是整个二维数组 arr 后面的空间的地址,类型为int(*)[2][5]即指向2行5列的数组的指针
  • 然后强制类型转换为int(*)类型即整型指针

对整型指针变量 ptr2:

  • *(arr+1)可以看成 arr[1],即二维数组 arr 第二行的数组名即二维数组 arr 第二行第一个元素的地址
  • 总的来说,整型指针 ptr2 指向二维数组 arr 第二行第一个元素即 6

对第一个问题*(ptr1 - 1)

就是二维数组 arr 最后一行最后一个元素即 10

对第二个问题*(ptr2 - 1)

就是二维数组第一行最后一个元素即5

在这里插入图片描述

六、程序求解

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

解析:at

对二级指针 pa:

  • pa 指向字符指针数组 a 的首元素字符串 abc

对 pa++:

  • pa 加 1 后指向字符指针数组 a 的第二个元素字符串 hello

对问题 *pa

就是字符指针数组 a 的第二个元素,按 %s 打印就是 hello

在这里插入图片描述

七、程序求解

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

  • cpp 指向 cp 的第一个元素 c+3,c+3 为字符指针数组 c 的第四个元素的地址

对第一个问题**++cpp

++cpp 表示 cp 的第二个元素 c+2 的地址,而 cp 的第二个元素指向 c 的第三个元素,因此**++cpp为字符指针数组 c 的第三个元素即字符串 POINT

  • 经过第一次打印后,cpp 变为指向 cp 的第二个元素 c+2 的指针

对第二个问题*-- * ++cpp + 3

在上一个问题之后,又一次 ++cpp,表示 cp 的第三个元素 c + 1 的地址,解引用后表示 cp 的第三个元素 c+1

接着是自减,结果为 c,即 c 首元素的地址

然后解引用,表示 c 的首元素(指向字符串"ENTER"首字母的字符指针)

最后 +3,表示字符串"ENTER"的第四个字母’E’的地址

按 %s 打印就是 ER

  • 经过第二次打印后,cpp 变为指向 cp 的第三个元素 c+1 的指针

对第三个问题*cpp[-2] + 3

在上一个问题之后,先看 cpp[-2],cpp[-2]可以看成*(cpp+(-2))*(cpp-2)即 cp 的第一个元素 c+3

然后解引用,表示 c 的第四个元素(指向字符串"FIRST"首字母的字符指针)

最后 +3,表示字符串"FIRST"的第四个字母’S’的地址

按 %s 打印就是 ST

对第四个问题cpp[-1][-1] + 1

此时,cpp 为指向 cp 的第三个元素 c+1 的指针

cpp[-1][-1]+1可以看成*(*(cpp -1) -1)+1

首先,*(cpp-1)表示 cp 的第二个元素 c+2

接着 -1 得 c+1

然后解引用得 c 的第二个元素(指向字符串"NEW"首字母的字符指针)

最后 +1,表示字符串"NEW"的第二个字母’E’的地址

按%s打印就是EW

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青春无限坑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值