C语言-指针进阶-常见笔试面试题详解(2)

指针笔试题

例1:

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    //&a + 1跳过一整个数组,然后强制类型转换成(int*)
    //所以指针变量ptr存放的是数组往后一个元素

    printf( "%d,%d", *(a + 1), *(ptr - 1));
    //a是首元素地址,+1得到第二个元素的地址,*解引用得到2,打印2
    return 0;
}

输出:

2 5

例2:

struct Test
{
    int Num;
    char *pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节,内容对齐
int main()
{
    //结构体Test的指针+1,跳过20个字节,转换成十六进制是0x00100014
    printf("%p\n", p + 0x1);
    //p被强制类型转换成(unsigned long),整形+1,结果是0x00100001
    printf("%p\n", (unsigned long)p + 0x1);
    //p被强制类型转换成(unsigned int*),无符号整形指针+1,跳过4个字节,结果是0x00100004
    printf("%p\n", (unsigned int*)p + 0x1);
    return 0;
}

输出:

00100014
00100001
00100004

注:

指针+1才是跳过该指针类型所占的字节大小,

例3:

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);
    //(&a + 1)跳过整个数组,ptr1指向的是数组后一个元素
    int *ptr2 = (int *)((int)a + 1);
    //a是首元素地址,强制类型转换成整形后+1,代表整形1的地址从起始位置往后跳了一个字节
    //所以ptr2指针指向的是整形1的地址从起始位置往后跳了一个字节的位置
    printf( "%x,%x", ptr1[-1], *ptr2);
    //prt1[-1]就是*(ptr1-1),向前跳一个整形,指向数组最后一个元素,*解引用后,打印4
    //我用的是小端环境,数据在内存中是倒着放的,指针指向整形1往后一个字节,访问的时候
    //指针访问四个字节,就将数组下一个元素整形2的第一个字节也包含了,所以打印20000000
    return 0;
}

输出:

4,2000000

例4:

#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    //(0,1),看清楚,这是个逗号表达式,所以
    //数组a其实存放的是{ 1, 3, 5 }
    int *p;
    p = a[0];
    printf( "%d", p[0]);
    return 0;
}

输出:

1

例5:

int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    //a的类型是int(*)[5]
    //p的类型是int(*)[4]
    printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    //p[4][2]==*(*(p+4)+2)
    //&p[4][2] - &a[4][2]==-4
    //地址不存在负数
    //-4的源码:1000 0000 0000 0000 0000 0000 0000 0100
    //    反码:1111 1111 1111 1111 1111 1111 1111 1011
    //    补码:1111 1111 1111 1111 1111 1111 1111 1100
    //           f    f    f    f    f    f    f    c
    return 0;
}

输出:

fffffffc,-4

例6:

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *ptr1 = (int *)(&aa + 1);//&aa是一个数组指针类型int(*p)[5]
    //&aa+1跳过整个数组
    int *ptr2 = (int *)(*(aa + 1));
    //aa是数组首行地址,+1得到第二行地址
    printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    //ptr-1向前跳一个整形,得到数组最后一个元素地址,*解引用得到10
    //ptr2-1向前跳一个整形,得到数组第一行最后一个元素地址,*解引用得到5
    return 0;
}

输出:

10,5

例7:

#include <stdio.h>
int main()
{
    char *a[] = {"work","at","alibaba"};
    //这个指针数组里存放的是三个字符串的首元素地址

    char**pa = a;
    //二级指针pa接收了数组a首元素地址

    pa++;
    //指针++,跳过4个字节,

    printf("%s\n", *pa);
    //*pa指向第二个字符串的首元素地址,打印at

    return 0;
}

输出:

at

例8:

#include <stdio.h>
 
int main()
{
    char* c[] = { "ENTER","NEW","POINT","FIRST" };
    //数组中存放四个字符串的首元素地址
 
    char** cp[] = { c + 3,c + 2,c + 1,c };
    //这个二级指针数组存放的字符串数组分别是:
    //{ "FIRST", "POINT", "NEW", "ENTER" }
 
    char*** cpp = cp;
    //三级指针cpp指向cp数组的首元素地址
 
    printf("%s\n", **++cpp);
    //cpp++,cpp指向cp数组第二个元素地址,*第一次解引用得到cp数组第二个元素(c+2)
    //*第二次解引用cp数组第二个元素,得到c数组第三个元素,打印 POINT
 
    printf("%s\n", *-- * ++cpp + 3);
    //cpp++,cpp指向cp数组第三个元素地址,*第一次解引用得到cp数组第三个元素(c+1)
    //(c+1)--后等于c,再解引用得到c数组第一个元素,然后+3跳过三个字节,打印 ER
 
    printf("%s\n", *cpp[-2] + 3);
    //*cpp[-2]就是**(cpp-2),cpp-2得到cp数组首元素地址,*第一次解引用得到cp数组第二个元素(c+3)
    //*第二次解引用cp数组第一个元素,得到c数组第四个元素,+3跳过三个字节,打印 ST
 
    printf("%s\n", cpp[-1][-1] + 1);
    //cpp[-1][-1]就是*(*(cpp-1)-1),cpp-1指向cp数组第二个元素地址,*得到cp数组第二个元素(c+2)
    //然后-1等于(c+1),*得到c数组第二个元素,+1跳过一个字节,打印 EW
 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值