• c语言进阶篇:指针(四)


    ✨作者介绍:大家好,我是摸鱼王胖嘟嘟,可以叫我小嘟💕
    ✨作者主页:摸鱼王胖嘟嘟的个人博客主页.🎉
    🎈作者的gitee: 小比特_嘟嘟的个人gitee
    🎈系列专栏: 【从0到1,漫游c语言的世界】
    ✨小嘟和大家一起学习,一起进步!尽己所能,写好每一篇博客,沉醉在自己进步的喜悦当中🤭。如果文章有错误,欢迎大家在评论区✏️指正。让我们开始今天的学习吧!😊
    请添加图片描述

    💻前言

    大家好~今天又来带大家学习指针了,今天要给大家带来的是指针和数组的一道非常重要的面试题,希望大家能够细心学习,有所收获!!

    🍁首先我们来回顾一些知识吧!

    🎈数组名的意义:

    🍁sizeof(数组名) - 数组名表示整个数组的-计算的是整个数组的大小。
    🍁&数组名 - 数组名表示整个数组,取出的是整个数组的地址。
    🍁除此之外,所有的数组名都是数组首元素的地址。

    🎈指针类型的意义:

    🍁指针的类型决定了指针在被解引用的时候可以访问几个字节。
    🍁指针的类型决定了指针±1操作的时候,跳过了几个字节,即指针的步长。

    🎈一维数组(整型数组):

    ✏️注意:不同的操作系统,字节的大小是不同的.4(x86) 8(x64)

    #include
    
    int main()
    {
    /一维数组
    	int a[] = { 1,2,3,4 };//4*4=16
    	printf("%d\n", sizeof(a));//16
    	//sizeof(数组名),sizeof内部单独放一个数组名,所以这里数组名a表示整个数组 
    	//—— 计算的是整个数组的大小,单位是字节
    	printf("%d\n", sizeof(a + 0));//4/8  - a + 0 是第一个元素的地址,sizeof(a + 0)计算的是地址的大小
    	printf("%d\n", sizeof(*a));//4    - *a是数组的第一个元素,sizeof(*a)计算的是第一个元素的大小
    	printf("%d\n", sizeof(a + 1));//4/8 -  a+1是第二个元素的地址,sizeof(a + 1)计算的是地址的大小
    	printf("%d\n", sizeof(a[1]));//4  -  计算的都是第二个元素的大小
    
    	printf("%d\n", sizeof(&a));//4/8  - &a虽然数组的地址,但是也是地址
    	printf("%d\n", sizeof(*&a));//16  *&a == a  - 计算的是数组的大小
    	//&a -- int (*p)[4] = &a;
    	printf("%d\n", sizeof(&a + 1));//4/8 - 跳过整个数组之后下一个空间的地址
    	printf("%d\n", sizeof(&a[0]));//4/8
    	//&a[0],是首元素的地址
    	//—— 计算的是首元素地址的大小
    	printf("%d\n", sizeof(&a[0] + 1));//4/8
    	//&a[0],是首元素的地址,&a[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

    🎉效果展示:
    在这里插入图片描述

    🎈字符数组:

    🍁使用sizeof 观察arr[] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’}

    #include
    
    int main()
    {
    //字符数组
    	char arr[] = { ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' };
    
    	printf("%d\n", sizeof(arr));//6
    	//—— 计算的是整个数组的大小
    	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
    	//arr[0]是第一个元素:字符'a',字符+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
    • 23
    • 24

    🎉效果展示:
    在这里插入图片描述
    🍁使用strlen 观察arr[] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’}

    #include
    
    int main()
    {
    //字符数组
    	char arr[] = { ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' };
    
    	printf("%d\n", strlen(arr));//随机值
    	//数组名是首元素的地址,strlen函数从首元素开始,直到遇到'\0'才会停止,而数组中没有'\0',所以是随机值。
    	printf("%d\n", strlen(arr + 0));//随机值
    	//原因同上
    	printf("%d\n", strlen(*arr));//error
    	//strlen函数接收的是地址,站在strlen函数上,它认为你传给它的就是地址。
    	//*arr是首元素,即'a',所以strlen(*arr)相当于strlen('a'),'a'的ASCII值是97,所以就相当于strlen(97),
    	//会把97当做地址传给strlen函数,但是97这个地址不是我的,是非法访问,野指针问题。
    	printf("%d\n", strlen(arr[1]));//error
    	//原因同上,传过去的地址不属于我,野指针问题
    	printf("%d\n", strlen(&arr));//随机值
    	printf("%d\n", strlen(&arr + 1));//随机值-6
    	printf("%d\n", strlen(&arr[0] + 1));//随机值-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

    strlen函数:
    🍁求字符串的长度。遇到 ‘\0’ 才会停止,计算的是从开始到 ‘\0’ 之前出现的字符个数。
    🍁接收的不是字符串本身,而是字符串首元素的地址,接收的是地址。
    即使写成类似这样:my_strlen(“abc”); strlen内部传了个字符串
    这串代码和,char arr[] = “abc”; my_strlen(arr); 没有任何区别。
    注意,字符串传给my_strlen传的不是字符串本身,传的是首元素a的地址,是要用指针来接收的。
    🍁strlen函数接收的参数类型是char*, 说明strlen函数会一个字节一个字节的读取数据,即一个字符一个字符的看是否是’\0’。
    若传过来的指针类型是char * *或char * [4]等,都会被转换成char * 类型。

    🍁使用sizeof 观察arr[] = “abcdef”

    #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));//4/8
    	printf("%d\n", sizeof(*arr));//1
    	printf("%d\n", sizeof(arr[1]));//1
    	printf("%d\n", sizeof(&arr));//4/8  char (*)[7]
    	printf("%d\n", sizeof(&arr + 1));//4/8
    	printf("%d\n", sizeof(&arr[0] + 1));//4/8
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    🍁使用strlen观察arr[] = “abcdef”

    #include
    
    int main()
    {
    	char arr[] = "abcdef";
    	//[a b c d e f \0]
    	printf("%d\n", strlen(arr));//6
    	printf("%d\n", strlen(arr + 0));//6
    	printf("%d\n", strlen(*arr));//error
    	printf("%d\n", strlen(arr[1]));//error
    	printf("%d\n", strlen(&arr));//6
    	printf("%d\n", strlen(&arr + 1));//随机值
    	//&arr,取出的是整个数组的地址,+1跳过整个数组,指向'\0'的后面,所以是从'\0'的后面往后数,是随机值
    	printf("%d\n", strlen(&arr[0] + 1));//5
    	//&arr[0],取出的是首元素的地址,+1是第二个元素的地址
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    🎈指针:

    #include
    int main()
    {
    	char* p = "abcdef";
    	//p中放的是字符串首元素的地址,即字符'a'的地址
    
    	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)
    	printf("%d\n", sizeof(&p));//4/8
    	//取出的是首元素地址的地址,一级指针变量p的地址,是个二级指针
    	printf("%d\n", sizeof(&p + 1));//4/8
    	//p指向首元素‘a',p的类型是char*,p指向的元素的类型是char,char是1个字节,p+1跳过1个字节
    	//&p指向p,&p的类型是char**,&p指向的元素类型是char*,char*是4个字节,&p+1跳过4个字节
    	//所以,&p+1跳过p,指向了p后面的那个空间
    	printf("%d\n", sizeof(&p[0] + 1));//4/8
    	//是第二个元素的地址,即'b'的地址
    	
    	printf("%d\n", strlen(p));//6
    	printf("%d\n", strlen(p + 1));//5
    	printf("%d\n", strlen(*p));//error
    	printf("%d\n", strlen(p[0]));//error
    	printf("%d\n", strlen(&p));//随机值1
    	//为什么是随机值?
    	//p指向字符'a',&p指向p,p中放的是地址,所以&p指向的是地址
    	//&p指向的空间和p指向的空间,是两个完全不同的空间。没有联系。
    	//因为strlen接收的是char*类型的地址,而&p的类型是char**,
    	//所以char**会被转换成char*类型,一个字节一个字节的往下找'\0'
    	//那为什么不是出错呢?
    	//因为p的空间已经开辟了,p是属于我当前这个程序的,所以&p不是野指针,不会和之前strlen(97)一样造成野指针出错。
    	printf("%d\n", strlen(&p + 1));//随机值2
    	//原因同上
    	//而且随机值2和随机值1没有联系,&p指向的是p,&p+1是跳过4个字节指向p的后面
    	//但是当&p和&p+1分别传给strlen函数时,因为strlen接收的是char*类型的地址,
    	//所以它们指向的元素的数据类型都会被强制转换成char*,然后一个字节一个字节的向后找'\0',
    	//也许&指向的元素和&p1+1指向的元素之间就有'\0'呢。
    	printf("%d\n", strlen(&p[0] + 1));//5
    	//&p[0] + 1 就相当于 p + 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
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    🎈二维数组:

    #include
    int main()
    {
    	//二维数组
    	int a[3][4] = { 0 };
    
    	printf("%d\n", sizeof(a));//48 = 3 * 4 *sizeof(int)
    	printf("%d\n", sizeof(a[0][0]));//4 - a[0][0] - 第一行第一个元素
    	printf("%d\n", sizeof(a[0]));//16
    	printf("%d\n", sizeof(a[0] + 1));//4 - a[0]作为数组名并没有单独放在sizeof内部,也没有取地址,表示第一行第一个元素的地址
    									 //	a[0] + 1表示第一行第二个元素的地址
    	printf("%d\n", sizeof(*(a[0] + 1)));//4  *(a[0] + 1)是第一行第二个元素
    	printf("%d\n", sizeof(a + 1));//4   a是二维数组的数组名,并没有取地址,也没有单独放在sizeof内部,表示二维数组首元素的地址
    								  // a + 1就是第二行首元素的地址
    	printf("%d\n", sizeof(*(a + 1)));//16    *(a + 1) - >a[1]   a + 1 是第二行的地址 *(a + 1)表示第二行
    	printf("%d\n", sizeof(&a[0] + 1));//4   a[0]是第一行的数组名,&a[0]取出的就是第一行的地址,&a[0] + 1取出的就是第二行的地址
    	printf("%d\n", sizeof(*(&a[0] + 1)));//16  &a[0] + 1是第二行的地址,*(&a[0] + 1)就是第二行
    	printf("%d\n", sizeof(*a));//16   *a  - > *(a + 0) - > a[0]
    							   //a作为二维数组的数组名,没有取地址,没有单独放在sizeof内部,
    							   //a就是首元素的地址,即第一行的地址,所以*a就是第一行的大小
    	printf("%d\n", sizeof(a[3]));//16
    	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
    二维数组中:int a[3][4] = { 0 };
     
    计算整个数组的大小: sizeof(a); 
    计算整个第一行的大小: sizeof(a[0]); sizeof(*a);
     
    计算第一行第二个元素的大小:  sizeof(a[0][1]); sizeof(*(a[0] + 1));
    计算第一行第二个元素的地址的大小: sizeof(&a[0][1]); sizeof(a[0] + 1);
     
    计算第二行的大小: sizeof(a[1]); sizeof(*(a + 1)); sizeof(*(&a[0] + 1));
    计算第二行的地址的大小: sizeof(&a[1]); sizeof(a + 1); sizeof(&a[0] + 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    🎈总结

    这篇对大家可能很难理解,为了能够更好的去理解这部分知识,大家可以去关注一下比特鹏哥对这部分知识的讲解.
    附链接:鹏哥C语言 - 121.指针进阶8

  • 相关阅读:
    [附源码]Java计算机毕业设计SSM钓鱼爱好者交流平台
    java计算机毕业设计web开发数码产品推荐平台系统设计与实现源码+mysql数据库+系统+lw文档+部署
    Go线程实现模型-G
    WPS/word 表格跨行如何续表、和表的名称
    KNN(上):数据分析 | 数据挖掘 | 十大算法之一
    实操 | 制造一个OOM,生成jvm的dump文件,并通过jvisualvm工具解析
    Rust模式匹配
    使用 HTML CSS 和 JavaScript 创建星级评分系统
    Java_Stream流式计算
    vue前端密码加密,springboot后端密码解密
  • 原文地址:https://blog.csdn.net/weixin_61341342/article/details/126059859