进阶指针习题

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
判断下列代码的输出结果
/*
解题思路:
1、首先明确此代码考察的是对sizeof的使用方法的熟悉程度
sizeof是一个计算数据大小的一个操作符,对于一个数组。
2、其次明确sizeof()里面的数组名表示的是什么含义
(1)sizeof(数组名),其中数组名表示的是整个数组
(2)(&数组名) ,其中数组名表示的是整个数组
3、对代码进行分析
*/

int main()
{
    //一维数组
    int a[] = { 1,2,3,4 };
    printf("%d\n", sizeof(a));//16             求整个数组的大小:4*4      
    printf("%d\n", sizeof(a + 0));//4/8        a+0表示的是指向数组首元素地址的指针移动0位,其本质还是指针
    printf("%d\n", sizeof(*a));//4             *a表示的是对指向数组首元素地址的指针进行解引用,得到的是数组的首元素 
    printf("%d\n", sizeof(a + 1));//4/8        与a+0类似
    printf("%d\n", sizeof(a[1]));//4           a[1]表示的是数组的首元素
    printf("%d\n", sizeof(&a));//4/8           &a表示的是对整个数组取地址,其本质还是个地址
    printf("%d\n", sizeof(*&a));//16           *&a表示的是对a取地址再进行解引用,其本质表示的是整个数组,相当于求数组的大小
    printf("%d\n", sizeof(&a + 1));//4/8       &a+1,其本质是地址
    printf("%d\n", sizeof(&a[0]));//4/8        &a[0] ——  a先与[0]结合,再&,表示的是对数组首元素取地址
    printf("%d\n", sizeof(&a[0] + 1));//4/8    与&a[0]类似
    //注:只要是地址(指针),其大小就是4个或者8个字节,32位系统占4个字节,64位系统占8个字节

    return 0;
}

#include<string.h>
int main()
{
    //字符数组
     char arr[] = { 'a','b','c','d','e','f' };
    printf("%d\n", sizeof(arr));//6      6*1
    printf("%d\n", sizeof(arr + 0));//1
    printf("%d\n", sizeof(*arr));//1
    printf("%d\n", sizeof(arr[1]));//4/8
    printf("%d\n", sizeof(&arr));//4/8
    printf("%d\n", sizeof(&arr + 1));//4/8
    printf("%d\n", sizeof(&arr[0] + 1));//4/8
    //strlen()参数部分需要的是地址
    printf("%d\n", strlen(arr));//随机值        由于strlen只有遇到\0才会停止查找,而数组中没有0,所以为随机值
    printf("%d\n", strlen(arr + 0));//随机值
    //printf("%d\n", strlen(*arr));//err
    //printf("%d\n", strlen(arr[1]));err
    //printf("%d\n", strlen(&arr));strlen接收的是const char*的类型,不接收数组指针类型
    //printf("%d\n", strlen(&arr + 1));//同理
    printf("%d\n", strlen(&arr[0] + 1));//随机值-1
    return 0;
}

int main()
{
    char arr[] = "abcdef";
    printf("%d\n", sizeof(arr));//7
    printf("%d\n", sizeof(arr + 0));//4/8
    printf("%d\n", sizeof(*arr));//1
    printf("%d\n", sizeof(arr[1]));//1
    printf("%d\n", sizeof(&arr));//4/8
    printf("%d\n", sizeof(&arr + 1));//4/8
    printf("%d\n", sizeof(&arr[0] + 1));//4/8

    printf("%d\n", strlen(arr));//6
    printf("%d\n", strlen(arr + 0));//6
    /*printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));//违法访问
    printf("%d\n", strlen(&arr));//err
    printf("%d\n", strlen(&arr + 1));*/
    printf("%d\n", strlen(&arr[0] + 1));//随机值


    return 0;
}

int main()
{
    const char *p = "abcdef";//将a的地址存在p指针中
    printf("%d\n", sizeof(p));//4/8
    printf("%d\n", sizeof(p + 1));//4/8
    printf("%d\n", sizeof(*p));//1
    printf("%d\n", sizeof(p[0]));//1      p[0]==*(p+0)   可以将p看成是数组名
    printf("%d\n", sizeof(&p));//4/8
    printf("%d\n", sizeof(&p + 1));//4/8
    printf("%d\n", sizeof(&p[0] + 1));//4/8
    //注意:strlen()函数里面传的参数的完整类型是const char*类型,若传参传入其他类型时,系统会进行抱错,在低版本编译器中只会报警告,严格来说是错误的
    printf("%d\n", strlen(p));//6
    printf("%d\n", strlen(p + 1));//5
    printf("%d\n", strlen(&p[0] + 1));//5    &p[0] + 1实际和p + 1表示结果是一样的
    return 0;
}

int main()
{
    //二维数组
    int a[3][4] = { 0 };
    printf("%d\n", sizeof(a));//48=12*4
    printf("%d\n", sizeof(a[0][0]));//4
    printf("%d\n", sizeof(a[0]));//16=4*4          sizeof(数组名)计算的是整个数组的大小
//二维数组可以看成是元素由一维数组构成的一维数组,a[0]可以看成是二维数组第一行的数组名,而sizeof(数组名)其中的数组名表示的是整个数组,而不是首元素地址         

    printf("%d\n", sizeof(a[0] + 1));//4/8            a[0] + 1表示的是首元素地址加1,即表示的是第一行的第二个元素地址。第二行首元素地址应为a[1]+0
    printf("%d\n", sizeof(*(a[0] + 1)));//4           *(a[0] + 1)表示的是第一行第二个元素
    printf("%d\n", sizeof(a + 1));//4/8               a + 1是第二行数组的地址
    printf("%d\n", sizeof(*(a + 1)));//16=4*4         表示第二行数组的元素       
    printf("%d\n", sizeof(&a[0] + 1));//4/8           a[0]可以看成是二维数组第一行的数组名,&a[0]表示的是第一行的整个数组的地址,&a[0]+1表示的是第二行的地址
    printf("%d\n", sizeof(*(&a[0] + 1)));//16=4*4     表示第二行数组的元素        
    printf("%d\n", sizeof(*a));//16=4*4               a是首元素地址,其实就是第一行的数组。*a即为第一行数组的元素
    printf("%d\n", sizeof(a[3]));//16                
    //a[3]表示的是第四行的地址,sizeof()内的表达式是不参与真是运算的!!!,只是根据()里的类型计算它的大小。与arr[0]其实是类似的
    return 0;
}
/*总结:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。*/

指针笔试题——求下列指针代码的结果
int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    /*&a,取出的是整个数组的地址,&a+1跳过的是整个数组。再将数组指针类型的指针转换成整形指针类型赋给ptr。注意,前面跳过数组时是跳了5个整形,而限制ptr-1只
    向前移了1个整形,所以最后指针指向的位置是第5个元素的地址,而非第一个元素的地址*/

    printf("%d,%d", *(a + 1), *(ptr - 1));//输出结果为2,5
    return 0;
}

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);//p是一个结构体指针,指针+1跳过整个一个结构体指针,也就是20个字节。换算成16进制则为0x 10 00 14
    printf("%p\n", (unsigned long)p + 0x1);//将p强转为一个无符号长整型,+1,则表示的是数值加1.直接在地址上+1即可,即0x100001
    printf("%p\n", (unsigned int*)p + 0x1);//将p强转为无符号整形指针类型,由于是整形,所以+1跳过四个字节。所以结果为0x100004
    return 0;
}

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);//&a——将整个数组a取地址并跨国整个数组,然后将数组指针强转为int*类型赋给ptr1
    int *ptr2 = (int *)((int)a + 1);//将a强转为整形,并+1。(整数+1,实际上相当于向后偏移一个字节)后,再将其强转为int*类型赋给ptr2
    printf("%x,%x", ptr1[-1], *ptr2);//结果为4,2000000
   // ptr1[1]可以看成是一个指向数组的整形指针向前挪动一位的数组。由于int类型的指针只能取出四个字节的空间,因此*pte2为2000000
    return 0;
}

 

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//{(0.1)}表示的是括号表达式,逗号表达式结果是最后一个表达式的结果
    int *p;
    p = a[0];
    printf("%d", p[0]);//p[0]相当于*(p+0),输出结果是1
    return 0;
}

 

 int main()
{
    int a[5][5];
    int(*p)[4];
    p = (int(*)[4])a;//将a的类型强转为(int(*)[4])并赋给p指针
    printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

//p[4][2]可以看成是*(*(p+4)+2)。答案为:FFFFFFFC,-4
    return 0;
}

 

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *ptr1 = (int *)(&aa + 1);//&arr为取出整个二维数组的地址,+1跳过整个二维数组,再将数组指针类型强转为int*类型赋给ptr1
    int *ptr2 = (*(aa + 1));//aa为第一行数组的地址,aa+1为第二行数组的地址,对其解引用为第二行首元素的地址(*(aa+1)可看成aa[1]),再赋给ptr2
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    //ptr1-1为将ptr1指针向左移动一个整形即4个字节的空间再对其解引用,答案为10
    //ptr2-1为在对第二行首元素指针进行向左移动4个字节的空间再对其解引用,答案为5

    return 0;
}

int main()
{
    const char *a[] = { "work","at","alibaba" };
    const char**pa = a;//把指针数组的首元素地址传给pa
    pa++;//表示的是第二个字符串的首元素地址
    printf("%s\n", *pa);//%s只有遇到\0才会停止打印,答案为:at
    return 0;
}

 

int main()
{
    const char *c[] = { "ENTER","NEW","POINT","FIRST" };
    const char**cp[] = { c + 3,c + 2,c + 1,c };
    const char***cpp = cp;
    printf("%s\n", **++cpp);
    printf("%s\n", *--*++cpp + 3);//cpp这样的值一直在发生变化,上卖弄对cpp++操作后的结果将保留到下一个求值的起始条件
    printf("%s\n", *cpp[-2] + 3);
    printf("%s\n", cpp[-1][-1] + 1);
    return 0;
}

//不懂重新看鹏哥视频p43

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值