• 指针进阶(3)


    9. 指针和数组笔试题解析

    在做题之前,我们再次明确一下数组名的理解:

    数组名是数组首元素的地址,但是有2个例外:

    1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
    2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

    接下来是一些笔试题:

    #include 
    
    int main()
    {
    	int a[] = { 1,2,3,4 };
     
    	printf("%d\n", sizeof(a));//4*4=16
    	printf("%d\n", sizeof(a + 0));//数组名a是数组首元素的地址,a+0还是首元素的地址,地址的大小4/8
    	printf("%d\n", sizeof(*a));//数组名a是数组首元素的地址,*a就是首元素,大小就是4个字节
    	printf("%d\n", sizeof(a + 1));//数组名a是数组首元素的地址,a+1是第二个元素的地址,地址的大小4/8
    	printf("%d\n", sizeof(a[1]));//第二个元素的大小就是4个字节
    	printf("%d\n", sizeof(&a));//&a是数组的地址,数组的地址也是地址,是地址4/8个字节
    	printf("%d\n", sizeof(*&a));//16个字节
    	//sizeof(*&a) --> sizeof(a) - 16
    	//&a --> int (*)[4]
    	//对整型指针解引用,拿到的是整型;对数组指针解引用,拿到的就是整个数组
    	printf("%d\n", sizeof(&a + 1));//&a+1相对于&a是跳过了整个数组,但是即使跳过了整个数组,&a+1依然是地址,是地址就是4/8个字节
    	printf("%d\n", sizeof(&a[0]));//&a[0]是首元素的地址,4/8个字节
    	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,是地址就是4/8个字节
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    #include 
    #include 
    
    int main()
    {
    	char arr[] = { 'a','b','c','d','e','f' };
     
    	printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,这里的arr表示整个数组,计算的是整个数组的大小,单位是字节,总共6个字节
    	printf("%d\n", sizeof(arr + 0));//arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节
    	printf("%d\n", sizeof(*arr));//arr表示数组首元素的地址,*arr就是首元素,大小1个字节
    	printf("%d\n", sizeof(arr[1]));//arr[1]就是第二个元素,大小是1个字节
    	printf("%d\n", sizeof(&arr));//&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8
    	printf("%d\n", sizeof(&arr + 1));//&arr + 1是跳过整个数组后的地址,是地址就是4/8个字节
    	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是4/8个字节
    	
    	printf("%d\n", strlen(arr));//因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结果就是随机值
    	printf("%d\n", strlen(arr + 0));//arr + 0是首元素的地址,和第一个一样,也是随机值
    	//printf("%d\n", strlen(*arr));//err  arr是数组首元素的地址,*arr就是数组首元素,就是'a' - 97
    	
    	//strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参
    	//strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
    	
    	//printf("%d\n", strlen(arr[1]));//err
    	printf("%d\n", strlen(&arr));//随机值  &arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计
    	printf("%d\n", strlen(&arr + 1));//随机值
    	printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,结果也是随机值
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    #include 
    #include 
    
    int main()
    {
    	char arr[] = "abcdef";//[a b c d e f \0]
     
    	printf("%d\n", sizeof(arr));//7
    	printf("%d\n", sizeof(arr + 0));//arr + 0 是首元素的地址 4/8
    	printf("%d\n", sizeof(*arr));//*arr其实就是首元素,1个字节
    	//*arr --> *(arr+0) -- arr[0]
    	printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,1个字节
    	printf("%d\n", sizeof(&arr));//&arr是数组的地址,是地址就是4/8个字节
    	printf("%d\n", sizeof(&arr + 1));//&arr + 1是跳过一个数组的地址,4/8
    	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址 4/8
    
    	printf("%d\n", strlen(arr));//6
    	printf("%d\n", strlen(arr + 0));//6
    	//printf("%d\n", strlen(*arr));//err
    	//printf("%d\n", strlen(arr[1]));//err
    	printf("%d\n", strlen(&arr));//6
    	printf("%d\n", strlen(&arr + 1));//随机值
    	printf("%d\n", strlen(&arr[0] + 1));//5
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    #include 
    #include 
    
    int main()
    {
    	char* p = "abcdef";
    
    	printf("%d\n", sizeof(p));//p是一个指针变量,大小就是4/8
    	printf("%d\n", sizeof(p + 1));//p+1是'b'的地址,是地址大小就是4/8个字节
    	printf("%d\n", sizeof(*p));//*p就是'a',就是1个字节
    	printf("%d\n", sizeof(p[0]));//p[0] --> *(p+0) --> *p  1个字节
    	printf("%d\n", sizeof(&p));//4/8
    	//&p -- char**
    	printf("%d\n", sizeof(&p + 1));//4/8
    	printf("%d\n", sizeof(&p[0] + 1));//4/8,&p[0] + 1得到的是'b'的地址
    
    	printf("%d\n", strlen(p));//6
    	printf("%d\n", strlen(p + 1));//5
    	//printf("%d\n", strlen(*p));//err
    	//printf("%d\n", strlen(p[0]));//err
    	printf("%d\n", strlen(&p));//随机值
    	printf("%d\n", strlen(&p + 1));//随机值
    	printf("%d\n", strlen(&p[0] + 1));//5
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    &p+1的指向


    #include 
    
    int main()
    {
    	int a[3][4] = { 0 };
    
    	printf("%d\n", sizeof(a));//3*4*4 = 48
    	printf("%d\n", sizeof(a[0][0]));//4
    	printf("%d\n", sizeof(a[0]));//a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
    	printf("%d\n", sizeof(a[0] + 1));//4/8
    	//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有&
    	//a[0]表示数组首元素的地址,也就是a[0][0]的地址
    	//所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节
    	
    	printf("%d\n", sizeof(*(a[0] + 1)));//4 计算的就是第一行第2个元素的大小
    	printf("%d\n", sizeof(a + 1));//4/8 a是数组首元素的地址,是第一行的地址(int(*)[4]),a+1就是第二行的地址
    	printf("%d\n", sizeof(*(a + 1)));//16
    	//1. *(a+1) --> a[1]  sizeof(*(a+1)) --> sizeof(a[1])计算的是第二行的大小
    	//2. a+1是第二行的地址(int(*)[4])  *(a+1)访问的是第二行的数组
    	
    	printf("%d\n", sizeof(&a[0] + 1));//4/8 &a[0]是第一行的地址(int(*)[4]),&a[0]+1是第二行的地址(int(*)[4])
    	printf("%d\n", sizeof(*(&a[0] + 1)));//16 计算的是第二行的大小
    	printf("%d\n", sizeof(*a));//计算的是第一行的大小 - 16
    	//1. a是数组首元素的地址,就是第一行的地址
    	//*a就是第一行
    	//2. *a --> *(a+0) --> a[0]
    
    	printf("%d\n", sizeof(a[3]));//16  a[3] --> int[4]
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    二维数组的相关理解
    对于以上代码中最后一行代码,我们再稍作解释:

    //编译    +    链接 --> 可执行程序 -->  运行  --> 结果
    //sizeof                              s = a + 2
    //因为sizeof在编译期间就已经处理了,所以在运行时就不会再执行s = a + 2这个代码了
    
    //表达式都有2个属性:
    //1. 值属性
    //2. 类型属性
    //s = a + 2 --> short
    //值属性:9
    
    #include 
    
    int main()
    {
    	int a = 7;
    	short s = 4;
    	printf("%d\n", sizeof(s = a + 2));//short 2
    	//sizeof内部的表达式是不会真的计算的,它只关注表达式最后的类型
    	printf("%d\n", s);//4
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    10. 指针笔试题

    #include 
    
    int main()
    {
    	int a[5] = { 1, 2, 3, 4, 5 };
    	int* ptr = (int*)(&a + 1);
    	printf("%d,%d", *(a + 1), *(ptr - 1));//2,5
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    #include 
    
    //由于还没学习结构体,这里告知结构体的大小是20个字节
    struct Test
    {
    	int Num;
    	char* pcName;
    	short sDate;
    	char cha[2];
    	short sBa[4];
    }*p = (struct Test*)0x100000;
    
    //假设p的值为0x100000。 如下表表达式的值分别为多少?
    //已知结构体Test类型的变量大小是20个字节
    int main()
    {
    	printf("%p\n", p + 0x1);//00100014  +1要跳过一个结构体(20个字节)
    	printf("%p\n", (unsigned long)p + 0x1);//00100001  整数+1就是+1
    	printf("%p\n", (unsigned int*)p + 0x1);//00100004 +1要跳过一个整型(4个字节)
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    //假设是小端存储
    //%x是以十六进制形式输出
    #include 
    
    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);//4,2000000
    	//ptr[-1] --> *(ptr-1)
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    指针笔试题3


    #include 
    
    int main()
    {
    	int a[3][2] = { (0, 1), (2, 3), (4, 5) };//这个二维数组里是逗号表达式,如果想把0,1放在第一行,要用{ },所以二维数组中存的是1,3,5,0,0,0
    	int* p;
    	p = a[0];//数组名是数组首元素地址 --> &a[0][0]
    	printf("%d", p[0]);//1   p[0] --> *(p+0) --> *p
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    #include 
    
    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]);//FFFFFFFC,-4
    	//-4
    	//10000000000000000000000000000100
    	//11111111111111111111111111111011
    	//11111111111111111111111111111100
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    指针笔试题5


    #include 
    
    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));//*(aa+1) --> aa[1] --> &aa[1][0]
    	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    #include 
    
    int main()
    {
    	char* a[] = { "work", "at", "alibaba" };
    	char** pa = a;
    	pa++;
    	printf("%s\n", *pa);///at
    	
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    指针笔试题7


    #include 
    
    int main()
    {
    	char* c[] = { "ENTER", "NEW", "POINT", "FIRST" };
    	char** cp[] = { c + 3, c + 2, c + 1, c };
    	char*** cpp = cp;
    	
    	printf("%s\n", **++cpp);//POINT
    	printf("%s\n", *-- * ++cpp + 3);//ER
    	printf("%s\n", *cpp[-2] + 3);//ST   *cpp[-2]+3 --> **(cpp-2)+3
    	printf("%s\n", cpp[-1][-1] + 1);//EW  *(*(cpp-1)-1)+1
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    一开始的指向关系:
    指针笔试题8(1)
    第一个printf
    指针笔试题8(2)
    第二个printf:
    指针笔试题8(3)
    第三个printf:
    指针笔试题8(4)
    第四个printf:
    指针笔试题8(5)

  • 相关阅读:
    PyCharm、Python、Django安装以及环境变量配置
    【unity3D】Scroll Rect组件—制作下滑列表
    【毕业设计】基于php+mysql+smarttemplate的图片共享系统设计与实现(毕业论文+程序源码)——图片共享系统
    科技赋能,创新发展!英码科技受邀参加2023中国创新创业成果交易会
    【docker容器 redis密码没有生效解决办法】
    如何选择向量数据库|Weaviate Cloud v.s. Zilliz Cloud
    PID 控制理论
    MySQL学习——选项文件的使用
    最近学习内容(2023-10-22)
    23种设计模式精讲
  • 原文地址:https://blog.csdn.net/weixin_73077334/article/details/134269696