游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

C语言指针经典知识汇总

  指针在C语言中是一块很重要的内容,也是比较难理解的一块内容,我们需要反复理解反复巩固才可以对其有所了解。之前也分享过指针相关的笔记,但是都比较杂,本篇笔记汇总一下指针相关的内容,包含了挺多指针相关的基础知识点。这篇笔记有点长,可以收藏下来慢慢阅读。复杂类型说明
  以下这部分内容主要来自《让你不再害怕指针》:
  要了解指针,多多少少会出现一些比较复杂的类型,所以,先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单。
  一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析。
  下面让我们先从简单的类型开始慢慢分析吧:intp;
  这是一个普通的整型变量。
  intp;
  首先从P处开始,先与结合,所以说明P是一个指针,然后再与int结合,说明指针所指向的内容的类型为int型。所以P是一个返回整型数据的指针。
  intp〔3〕;
  首先从P处开始,先与〔〕结合,说明P是一个数组,然后与int结合,说明数组里的元素是整型的,所以P是一个由整型数据组成的数组。
  intp〔3〕;
  首先从P处开始,先与〔〕结合,因为其优先级比高,所以P是一个数组,然后再与结合,说明数组里的元素是指针类型,然后再与int结合,说明指针所指向的内容的类型是整型的,所以P是一个由返回整型数据的指针所组成的数组。
  int(p)〔3〕;
  首先从P处开始,先与结合,说明P是一个指针然后再与〔〕结合与()这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int结合,说明数组里的元素是整型的。所以P是一个指向由整型数据组成的数组的指针。
  intp;
  首先从P开始,先与后再与结合,说明指针所指向的元素是指针,然后再与int结合,说明该指针所指向的元素是整型数据。由于二级以上的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针。
  intp(int);
  从P处起,先与()结合,说明P是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数然后再与外面的int结合,说明函数的返回值是一个整型数据。
  int(p)(int);
  从P处开始,先与指针结合,说明P是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int结合,说明函数有一个int型的参数,再与最外层的int结合,说明函数的返回类型是整型,所以P是一个指向有一个整型参数且返回类型为整型的函数的指针。
  说到这里也就差不多了,我们的任务也就这么多,理解了这几个类型,其它的类型对我们来说也是小菜了。不过我们一般不会用太复杂的类型,那样会大大减小程序的可读性,请慎用,这上面的几种类型已经足够我们用了。
  分析指针的方法
  指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型、指针所指向的类型、指针的值(指针所指向的内存区)、指针本身所占据的内存区。让我们分别说明。
  先声明几个指针放着做例子:(1)intptr;(2)charptr;(3)intptr;(4)int(ptr)〔3〕;(5)int(ptr)〔4〕;
  1、指针的类型
  从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:(1)intptr;指针的类型是int(2)charptr;指针的类型是char(3)intptr;指针的类型是int(4)int(ptr)〔3〕;指针的类型是int()〔3〕(5)int(ptr)〔4〕;指针的类型是int()〔4〕
  2、指针所指向的类型
  当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
  从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符去掉,剩下的就是指针所指向的类型。例如:(1)intptr;指针所指向的类型是int(2)charptr;指针所指向的的类型是char(3)intptr;指针所指向的的类型是int(4)int(ptr)〔3〕;指针所指向的的类型是int()〔3〕(5)int(ptr)〔4〕;指针所指向的的类型是int()〔4〕
  在指针的算术运算中,指针所指向的类型有很大的作用。
  3、指针的值
  指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。
  指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。
  以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
  指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
  以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指向的类型是什么?该指针指向了哪里?(重点注意)。
  4、指针本身所占据的内存区
  指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式(后面会解释)是否是左值时很有用。
  指针的算术运算
  指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的,以单元为单位。
  这在内存上体现为:相对这个指针向后偏移多少个单位或向前偏移了多少个单位,这里的单位与指针变量的类型有关。在32bit环境下,int类型占4个字节,float占4字节,double类型占8字节,char占1字节。
  【注意】一些处理整数的操作不能用来处理指针。例如,可以把两个整数相乘,但是不能把两个指针相乘。示例程序includestdio。hintmain(void){inta10,paa;floatb6。6,pbb;charca,pcc;doubled2。14e9,pdd;最初的值printf(pa0d,pb0d,pc0d,pd0d,pa,pb,pc,pd);加法运算pa2;pb2;pc2;pd2;printf(pa1d,pb1d,pc1d,pd1d,pa,pb,pc,pd);减法运算pa1;pb1;pc1;pd1;printf(pa2d,pb2d,pc2d,pd2d,pa,pb,pc,pd);return0;}
  运行结果为:pa06422268,pb06422264,pc06422263,pd06422248pa16422276,pb16422272,pc16422265,pd16422264pa26422272,pb26422268,pc26422264,pd26422256
  解析:
  举例说明pa0pa1pa2的过程,其他类似。pa02sizeof(int)pa1,pa11sizeof(int)pa2。因为pa为int类型的指针,所以加减运算是以4字节(即sizeof(int))为单位地址向前向后偏移的。看下图:
  如图:pa1所指向的地址在pa0所指向地址往后8字节处,pa2指向地址在pa1指向地址往前4字节处。
  从本示例程序中,还可以看出:连续定义的变量在内存的存储有可能是紧挨着的,有可能是分散着的。
  数组和指针的联系
  数组与指针有很密切的联系,常见的结合情况有以下三种:数组指针指针数组二维数组指针
  1、数组指针
  数组指针:指向数组的指针。如:intarr〔〕{0,1,2,3,4};intparr;也可写作intparr〔0〕
  也就是说,p,arr,arr〔0〕都是指向数组的开头,即第0个元素的地址。
  如果一个指针p指向一个数组arr〔〕的开头,那么pi为数组第i个元素的地址,即arr〔i〕,那么(pi)为数组第i个元素的值,即arr〔i〕。
  同理,若指针p指向数组的第n个元素,那么pi为第n1个元素的地址;不管p指向了数组的第几个元素,p1总是指向下一个元素,p1也总是指向上一个元素。
  下面示例证实了这一点:includestdio。hintmain(void){intarr〔〕{0,1,2,3,4};intparr〔3〕;也可以写作intparr3;printf(d,d,d,d,d,(p3),(p2),(p1),(p),(p1));return0;}
  运行结果为:0,1,2,3,4
  2、指针数组
  指针数组:数组中每个元素都是指针。如:inta1,b2,c3;intarr〔3〕{a,b,c};
  示例程序:includestdio。hintmain(void){inta1,b2,c3;定义一个指针数组intarr〔3〕{a,b,c};也可以不指定长度,直接写作intparr〔〕定义一个指向指针数组的指针intparrarr;printf(d,d,d,arr〔0〕,arr〔1〕,arr〔2〕);printf(d,d,d,(parr0),(parr1),(parr2));return0;}
  第一个printf()语句中,arr〔i〕表示获取第i个元素的值,该元素是一个指针,还需要在前面增加一个才能取得它指向的数据,也即arr〔i〕的形式。
  第二个printf()语句中,parri表示第i个元素的地址,(parri)表示获取第i个元素的值(该元素是一个指针),(parri)表示获取第i个元素指向的数据。
  指针数组还可以和字符串数组结合使用,请看下面的例子:includestdio。hintmain(void){charstr〔3〕{helloC,helloC,helloJava};printf(sss,str〔0〕,str〔1〕,str〔2〕);return0;}
  运行结果为:helloChelloChelloJava
  3、二维数组指针
  二维数组指针:指向二维数组的指针。如:inta〔3〕〔4〕{{0,1,2,3},{4,5,6,7},{8,9,10,11}};int(p)〔4〕a;
  a〔3〕〔4〕表示一个3行4列的二维数组,其所有元素在内存中是连续存储的。
  请看如下程序:includestdio。hintmain(void){inta〔3〕〔4〕{{0,1,2,3},{4,5,6,7},{8,9,10,11}};inti,j;for(i0;i3;i){for(j0;j4;j){printf(a〔d〕〔d〕d,i,j,a〔i〕〔j〕);}}return0;}
  运行结果为:a〔0〕〔0〕6422216a〔0〕〔1〕6422220a〔0〕〔2〕6422224a〔0〕〔3〕6422228a〔1〕〔0〕6422232a〔1〕〔1〕6422236a〔1〕〔2〕6422240a〔1〕〔3〕6422244a〔2〕〔0〕6422248a〔2〕〔1〕6422252a〔2〕〔2〕6422256a〔2〕〔3〕6422260
  可见,每个元素的地址都是相差4个字节,即每个连续在内存中是连续存储的。
  按照以上定义可归纳出如下4个结论:
  (1)p指向数组a的开头,也即第1行;p1前进一行,指向第2行。
  (2)(p1)表示取第2行元素(一整行元素)。
  (3)(p1)1表示第2行第2个元素的地址。
  (4)((p1)1)表示第2行第2个元素的值。
  综上4点,可得出如下结论:aipi(ai)(pi)a〔i〕〔j〕p〔i〕〔j〕(a〔i〕j)(p〔i〕j)((ai)j)((pi)j)
  以上就是数组与指针常用的三种结合形式。
  指针与数组的区别
  数组与指针在多数情况是可以等价的,比如:intarray〔10〕{0,1,2,3,4,5,6,7,8,9},value;valuearray〔0〕;也可写成:valuearray;valuearray〔3〕;也可写成:value(array3);valuearray〔4〕;也可写成:value(array4)
  但也有不等价的时候,比如如下三种情况:数组名不可以改变,而指向数组的指针是可以改变的。字符串指针指向的字符串中的字符是不能改变的,而字符数组中的字符是可以改变的。求数组长度时,借用数组名可求得数组长度,而借用指针却得不到数组长度。
  1、区别一
  数组名的指向不可以改变,而指向数组的指针是可以改变的。
  请看如下代码:includestdio。hintmain(void){inta〔5〕{0,1,2,3,4},pa;chari;数组遍历方式一for(i0;i5;i){printf(a〔d〕d,i,p);}数组遍历方式二for(i0;i5;i){printf(a〔d〕d,i,a);}return0;}
  数组遍历方式一:使用指针遍历数组元素,p等价于(p),即指针指向的地址每次后移一个单位,然后再取地址上的值。这里的一个单位是sizeof(int)个字节。
  数组遍历方式二:使用数组名自增遍历数组元素,编译出错,错误如下:error:valuerequiredasincrementoperand
  因为数组名的指向是不可以改变的,使用自增运算符自增就会改变其指向,这是不对的,数组名只能指向数组的开头。但是可以改为如下遍历方式:for(i0;i5;i){printf(a〔d〕d,i,(ai));}
  这可以正确遍历数组元素。因为(ai)与a〔i〕是等价的。
  2、区别二
  字符串指针指向的字符串中的字符是不能改变的,而字符数组中的字符是可以改变的。
  请看如下代码:字符串定义方式一charstr〔〕happy;字符串定义方式二charstrhappy;
  字符串定义方式一:字符串中的字符是可以改变的。如可以使用类似str〔3〕q这样的语句来改变其中的字符。原因就是:这种方式定义的字符串保存在全局数据区或栈区,是可读写的。
  字符串定义方式二:字符串中的字符是不可以改变的。原因就是:这种方式定义的字符串保存在常量区,是不可修改的。
  2、区别三
  求数组长度时,借用数组名可求得数组长度,而借用指针却得不到数组长度。
  请看如下代码:includestdio。hintmain(void){inta〔〕{0,1,2,3,4},pa;charlen0;求数组长度方式一printf(方式一:lend,sizeof(a)sizeof(int));求数组长度方式二printf(方式二:lend,sizeof(p)sizeof(int));return0;}
  运行结果方式一:len5方式二:len1
  求数组长度方式一:借用数组名来求数组长度,可求得数组有5个元素,正确。
  求数组长度方式二:借用指针求数组长度,求得长度为1,错误。原因是:
  p只是一个指向int类型的指针,编译器不知道其指向的是一个整数还是指向一个数组。sizeof(p)求得的是p这个指针变量本身所占用的字节数,而不是整个数组占用的字节数。
  下面还需要注意数组名的一个问题:声明了一个数组TYPEarray〔n〕,则数组名是一个常量指针,该指针的值是不能修改的,即类似array的表达式是错误的。
  指针函数与函数指针
  函数、指针这两个词结合的顺序不同其意义也不同,即指针函数与函数指针的意义不同。
  1、指针函数
  指针函数的本质是一个函数,其返回值是一个指针。示例如下:intpfun(int,int);
  由于的优先级低于()的优先级,因而pfun首先和后面的()结合,也就意味着,pfun是一个函数。即:int(pfun(int,int));
  接着再和前面的结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun是一个返回值为整型指针的函数。
  指针函数示例程序如下:includestdio。h这是一个指针函数的声明intpfun(intarr,intn);intmain(void){intarray〔〕{0,1,2,3,4};intlensizeof(array)sizeof(array〔0〕);intp;inti;指针函数的调用ppfun(array,len);for(i0;ilen;i){printf(array〔d〕d,i,(pi));}return0;}这是一个指针函数,其返回值为指向整形的指针intpfun(intarr,intn){intparr;returnp;}
  程序运行结果如下:
  主函数中,把一个数组的首地址与数组长度作为实参传入指针函数pfun里,把指针函数的返回值(即指向数组的指针)赋给整形指针p。最后使用指针p来遍历数组元素并打印输出。
  2、函数指针
  函数指针其本质是一个指针变量,该指针变量指向一个函数。C程序在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。函数指针示例:声明一个函数指针int(fptr)(int,int);函数指针指向函数funcfptrfunc;或者fptrfunc;
  func是一个函数名,那么func与func都表示的是函数的入口地址。同样的,在函数的调用中可以使用:方式一:func(),也可以使用方式二:(fun)()。这两种调用方式是等价的,只是我们平时大多都习惯用方式一的调用方法。
  至于为什么func与func的含义相同,《嵌入式Linux上的C语言编程实践》这本书中有如下解释:
  对于函数func来说,函数的名称就是函数代码区的常量,对它取地址(func)可以得到函数代码区的地址,同时,func本身也可以视为函数代码区的地址。因此,函数名称和对其取地址其含义是相同的。
  函数指针示例程序如下:includestdio。hintadd(inta,intb);intmain(void){int(fptr)(int,int);定义一个函数指针intres;fptradd;函数指针fptr指向函数add通过函数指针调用函数res(fptr)(1,2);等价于resfptr(1,2);printf(abd,res);return0;}intadd(inta,intb){returnab;}
  程序运行结果如下:
  以上就是关于指针函数与函数指针的简单区分。其中,函数指针广泛应用于嵌入式软件开发中,其常用的两个用途:调用函数和做函数的参数。
  以上就是本次的分享,如有错误,欢迎指出!谢谢

现在入手佳能5D4如何?现在已经是2019年了,作为曾经的单反老大佳能在近些年来显得一身疲态,虽然5D4是一台很好的单反相机,但是也仅限于在佳能品牌中,如果用他的性能来对比尼康、索尼、5D4真心差的比……今日区块链资讯1。美国副总检察长LisaMonaco在当地时间周四宣布,联邦调查局(FBI)正在创建一个致力于加密货币的专业团队,称为虚拟资产犯罪调查部。该部门将包括加密专家,并拥有最终可能……美国强索台积电三星芯片数据是一石三鸟,意在掌控全球半导体产业美国商务部上周再次举行半导体高峰会,要求与会的台积电、三星等晶圆代工厂交出被视为商业机密的库存量、订单、销售记录、客户等数据。提高芯片供应链透明度的理由冠冕堂皇,似乎有解决全球……三星电子接近敲定170亿美元芯片厂选址或将落脚德州财联社(上海,编辑卞纯)讯,据媒体援引知情人士的话报道,韩国科技巨头三星电子(SamsungElectronics)即将敲定在美国德克萨斯州威廉森县(WilliamsonCou……数据管理人工智能商业化落地的必修课中国经济导报中国战略新兴产业杂志中国发展网记者杜壮目前人工智能市场发展依然火热,各行各业对数据的需求也呈现井喷态势。然而现在很多企业的大部分非结构化数据无法用于AI(人工……财经金融企业负面舆情监测怎么做?做法一:构建舆情监测系统当前,网上的财经金融数据信息多且杂,又是实时在更新,依靠传统的方式监测行不通。因此,可以通过构建一套专业的网络舆情监测系统辅助监测。如鹰眼速读网系……2021年618哪一款手机最值得买?高性价比手机推荐和选购指本篇文章从千元价位逐步以上推荐,有预算的各位直接滑倒自己喜欢的地方即可。千元机推荐:学生党与老年机首选!RedmiNote94G到手价899元亮点:4GB12……小零食,大市场!小零食,大市场。一袋瓜子,就可以成就一家上市公司。对此,资本市场并无怀疑。商务部曾在《消费升级背景下零食行业发展报告》中指出,从2006年至2016年,仅10年时间……业界可持续交通须通过科技及工程领域的创新来实现人民网北京10月16日电(记者乔雪峰)当今社会,新一轮科技革命和产业变革正在全球范围蓬勃兴起,新技术与交通运输深度融合,智能铁路、自动驾驶、无纸化出行等创新场景不断涌现,在人类……真快乐APP改版升级乐购融合国美开启娱乐电商新征程上线9个月,真快乐APP赶在双十一前夕完成了一场全新的改版升级。10月21日下午,国美发布双11全民快乐季活动,同时宣布旗下真快乐App改版后进入试运营阶段。改版后的真快……小程序外包开发上线但很多实体店铺,对小程序并不是十分了解,所以往往就会持以怀疑的态度,故而很难下定决心来制作小程序。北京木奇移动技术有限公司,专业的APP外包开发公司,欢迎洽谈合作。有鉴于此,下……客观分析怎么选择扫地机器人今天给大家整体分析一下,希望能帮助到你,首先要清楚我们为什么需要扫地机器人呢?我认为扫地机器人适合的人群1,孝敬父母,爸妈年纪大了腰痛腿痛2,鼻炎过敏体质,春秋时期……
甄嬛传甄嬛如果不是双生子,结局必死无疑甄嬛传中一直以为开始时以为后宫的大boss是年羹尧的妹妹,依靠拥有军功在身的哥哥,恃宠而娇的年世兰,年世兰死后,表面慈眉善目的皇后,其实,在太后去世前,后宫的所有争斗,下指导棋……微信社群如何运营?高效管理才是王道随着微信群越来越多,在微信群管理中,如何才能让用户不屏蔽群消息?这是很多运营者以及微电商人考虑的问题。对于很多运营者而言,在玩社群时目标都非常明确,就是将群内成员转化为客……604只个股毛利率超50TOP50均超85截至2021年4月30日,沪深两市共有4181家上市公司发布2020年销售毛利率,整体销售毛利率为32。78。其中,604只个股毛利率50以上,TOP50均超85在进行价……挑战者值得关注的新型核能技术创业公司资本实验室今日创新观察聚焦前沿科技创新与传统产业升级核能的优势自不待言。通过利用原子裂变技术,核能可以从工业过程到家庭用电,为之提供可靠而丰富的低碳能源供应,也是对……抚州五菱荣光店内直降0。055万元,欢迎到店鉴赏刚刚小编在车友圈看到好多朋友都在讨论五菱荣光最高优惠1。23,这么诱人的降价幅度,想要购车的朋友们不考虑一下趁机拿下?五菱汽车抚州国鼎销售中心店,活动时间即日起到10月29日,……广汽首款氢燃料电池车由如祺出行示范运营等7条快讯1、广汽首款氢燃料电池车由如祺出行示范运营近日,广汽集团首款氢燃料电池车于如祺出行平台开启示范运营,为广州市民带来更加节能、环保的新能源汽车出行体验。如祺出行是粤港……练就不在乎的勇气什么该在意什么不必不在乎,是修养,是气度。很直白的书名,想要告诉当下活得太累的人,他人意见其实没你想的那么重要。这本不厚的小书特别适合在旅途过程中前往目的地的路上静静地翻读几页看看。……像手机一样好用的车载智慧屏!华为智选车载智慧屏只要16992020年12月21日,在东莞举行的华为全屋智能及智慧屏新品发布会上,全新华为智选车载智慧屏正式与消费者见面。华为智选车载智慧屏是首款搭载分布式技术的车载终端设备,同时也是HU……高色域量子点RAPIDIPS,微星MAG274QRFQD电竞笔者最近收到一台微星OptixMAG274QRFQD电竞显示器,采用27英寸2K分辨率RAPIDIPS屏幕,支持165Hz刷新率以及1msGTG(灰度到灰度)响应时间,从规格上……广西铁塔超5亿元综合代维招标活动因收到异议暂停于11月15日公布了中标结果的中国铁塔广西分公司2016年至2019年综合代维服务采购项目,因收到对该项目的异议,宣布暂停该项目的招标投标活动,成为今年铁塔公司综合代维第一例因……守序中立即善良SoftearsRSV五单元动铁曾几何时,国产塞子是售价不过千的,几千几万那是美系日系的天下,舒尔威士顿音特美UE、索尼铁三角AKG森海中高端塞子,那都人家的战场。究其原因,一方面是声音方面的技术,人家……亲身体验叮咚课堂少儿英语课前课中课后全面测评今天刚参加完孩子学校的亲子英语角活动,小孩的表现不错,词汇、短语张口就来,令人惊喜。对比一年前的亲子英语角活动,孩子的确成长了很多,再回想一下最近一周以来,孩子爸也夸奖过他的口……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网