已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C指针的用法总结char *p, *p, *p;char p,p,p;char *p,*p,*p,*p,*(*p),(*p),(*p); void (*pFun)(int i);大神们看到这些东西脑袋里一定像蓝天白云一样清晰明了。(1)关于指针与数组的存储a、指针和数组在内存中的存储形式 数组pN创建时,对应着内存中一个数组空间的分配,其地址和容量在数组生命周期内一般不可改变。数组名p本身是一个常量,即分配数组空间的地址值,这个值在编译时会替换成一个常数,在运行时没有任何内存空间来存储这个值,它和数组长度一起存在于代码中(应该是符号表中),在链接时已经制定好了;而指针*p创建时,对应内存中这个指针变量的空间分配,至于这个空间内填什么值即这个指针变量的值是多少,要看它在程序中被如何初始化,这也决定了指针指向哪一块内存地址。b、指针和数组的赋值与初始化 根据上文,一般情况下,数组的地址不能修改,内容可以修改;而指针的内容可以修改,指针指向的内容也可以修改,但这之前要为指针初始化。如:int p5;p=p+1; 是不允许的而p0=1; 是可以的;/int *p;p=p+1; 是允许的p0=1; 是不允许的,因为指针没有初始化;/int i; int *p=&i;p0=1; 是允许的; 对于字符指针还有比较特殊的情况。如:char * p=abc;p0=d; 是不允许的 为什么初始化了的字符指针不能改变其指向的内容呢?这是因为p指向的是“常量”字符串,字符串abc实际是存储在程序的静态存储区的,因此内容不能改变。这里常量字符串的地址确定在先,将指针指向其在后。 而char p=abc;p0=d; 是允许的 这是因为,这个初始化实际上是把常量直接赋值给数组,即写到为数组分配的内存空间。这里数组内存分配在先,赋值在后。(2)关于一些表达式的含义char *p, *p, *p;char p,p,p;char *p,*p,*p,*p,*(*p),(*p),(*p); 能清晰地知道以上表达式的含义吗?(知道的去死!)第一组:char *p, *p, *p; 分别为char指针;char*指针,即指向char*类型数据地址的指针;char*指针,即指向char*类型数据的指针;他们都是占4字节空间的指针。如:char c=a;char *p=&c;char *p1=&p;char *p2=&p1; cout*p2endl;第二组:char p,p,p; 分别为一维,二维和三维char型数组,即数组,数组的数组,的数组。可以如下的方式进行初始化:char pp3=ab;char pp133=ab;char pp2333=ab; 现在我们尝试使用第二组三个数组名对应为第一组三个指针赋值,直接赋值的结果如下:p=pp; /正确p1=pp1; /错误p2=pp2; /错误 为什么p1和p2的赋值会出错呢?原因是数组名为给指针赋值的规则不是递归的,即数组的数组可以为数组的指针赋值,而不可以为指针的指针赋值。这里先了解到这个抽象的规则,下面讲完第三组表达式,等我们知道数组的指针和指针的数组如何书写后再对这一问题举例说明。第三组:char *p,*p,*p,*p,*(*p),(*p),(*p); 这一类表达式的解析方法如下: 首先把整个表达式分为三部分, 数据类型和星号部分+p或括号内内容部分+中括号部分如:char *(*p)分为char* ,(*p) 和 “char*”表示最内层存储的数据类型“(*p)”表示最外层指针“”表示中间层数组(维数=中括号数目),因此上式表示一个一维数组的指针p,数组中的元素的数据类型是指针char*。同理,char (*p)表示,一个二维数组的指针的指针,数组元素的数据类型是char。这里如果表达式中间没有括号(如*p),则实际上是一个数组,如果最右没有中括号(如*p),则实际上是一个指针。下面通过赋值表达式来理解这些表达式的含义:char c=a;char *pc=&c;char *p3,*p133,*p23,*p333,*(*p4)3,(*p5)3,(*p6)33,(*(*p7)3;p1=pc;p100=pc;p20=&pc;p300=&pc;(*p4)0=pc;(*p5)0=c;(*p6)00=c;(*p7)0=c; 注意,(*(*p7)3和(*p5)3是等价的。 这里再继续上一小节讲一下数组名给指针赋值的问题。 事实上可以对等赋值的数组和指针关系如下(表示“赋值给”):数组指针 : p*p指针的数组指针的指针 : *p*p指针的指针的数组的指针的指针的指针 : *p*p。或数组的数组数组的指针 : p(*p)数组的数组的数组的数组的数组的指针 : p(*p)总之,最外层的数组可以转换指针,往内层不递归。(3)关于上述表达式的长度 求一个表达式的“长度”,首先分清表达式实际表示的是一个数组还是一个指针;如果是指针,则长度为4byte;如果为数组则要计算实际存储的总元素个数和元素的数据类型。另外要注意要求的是数组元素个数还是数组总字节数;如:*(*p)33 由上文可知上式表示一个指针,因此长度为4byte;而*p333 表示一个二维数组,数组元素类型为指针的指针,因此长度为3*3*4=36; 注意,标准C中sizeof函数求得的是总字节数而非数组长度。(4)关于函数的指针返回值和指针参数 指针作为返回值要注意的地方是不要返回局部数据的指针。如:char * fun(void)char i=a;return (&i); 调用函数fun得不到值a,原因是函数返回后,局部数据(在栈中)被析构,数据内存被回收,指针指向的数据没有意义; 可以改为:char * fun(void)char i=a;char *p=(char *)malloc(5);If(p!=NULL) p0=i, p1=0;return (p); 这里使用malloc分配了内存(在堆中)在函数返回后依然有效。 这里还没完,因为有一天我使用了下面的代码:char * fun(void)char *p=abc;return (p);发现虽然p定义为局部变量,但返回也是正确的。还记得上面讲到的常量字符串存储位置吗?指针p实际指向了静态数据区,这里的char *p相当于const char *p,这样的数据在函数返回后是不会被立刻回收掉的。 指针作为参数主要用于修改指针指向的数据内容,但修改指针的值无效,如char * fun(char *p)char i=a;p=(char *)malloc(5);p0=i;return p; 因为传递的是一个指针副本(形参指针和实参指针的值相同,但不是同一个指针),不会影响调用方的实参值。(诡异的vs2012貌似可以通过形参将实参的值改掉!不过还是不要冒这个险为好了)。(5)关于const修饰符 const修饰符用于指针时也非常纠结。 首先要分清const char *p和char* const p。 const char *p是指向const对象的指针,即对象是只读的,而指针不是。使用const对象的指针要注意两点:一是不能将其赋值给非const对象的指针,如:const char* p;char *p1=p; /不允许的 当然,直接使用非const指针指向const对象也是不合法的,如:const char c;char *p1=&c;/不允许的, 这是要避免通过上述p1改变const对象的值。 二是可以将非const对象的地址赋值给指向const对象的指针,但是试图使用这个指针改变变量的值是非法的,如:char c=a; const char* p=&c;/允许的*p=b;/不允许的 char* const p是const指针,即指向对象可编辑,但指针本身不可修改,这一点类似于数组。如:char c=a; char* const p=&c;*p=b;/允许的p+;/不允许的 区分两者的方法是,看const是否靠近指针名,如果是则为const指针,否则为const对象。这个助记方法的前提是char要和*号靠在一起,因为const char* p=char const *p。另外,还有const char* const p,自然是指向const对象的const指针了。(6)关于指针函数 首先注意指针函数和函数指针的区别,前者是指“返回指针的函数”,这在上文中有提到,而后者是指“指向函数的指针”。 函数指针的定义方法为,将“函数名”替换为“(*函数指针名)”,如: 指向一个声明为void fun(int a)的函数指针可以定义为 void (*pFun)(int a)或void (*pFun)(int ),注意这里函数指针pFun只能指向和fun有相同返回类型(void)和参数类型(int)的一类函数,另外定义中()也不是摆设,去掉()会被看做是返回值为void*类型的函数声明。举个例子:void fun(int a)coutaendl; int main()void (*pFun)(int);pFun=&fun; /(1)*(pFun)(1); /(2) 事实上,上式中的(1)(2)行做如下几种替换也是正确的:a、pFun=fun; pFun(1); b、pFun=&fun; pFun(1); c、pFun=fun; *(pFun)(1); 如果有什么疑问的话,可以接着尝试用如下方式直接调用函数fun:(*fun)(1); 运行的结果也是正确的!这要怎么解释呢? 其实,fun不仅仅作为函数名,它同pFun一样也是一个函数指针,只不过是函数指针常量。为了书写方便,c语言开发者允许将函数指针调用直接写成类似fun()的形式,同样函数指针变量赋值也可以写成类似pFun=&fun的形式。值得注意的是,函数声明的格式还是比较严格的,如:void fun(int ); /不能写成void (*fun)(int )。 同样,void (*pFun)(int ); /不能写成void pFun(int )。 为了方便,我们还可以定义函数指针类型,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年广东省英德市高三历史上册期末考试考试卷汇编附答案
- 2025年云南省景洪市高考历史测试卷(名师系列)附答案
- 第六单元检测卷 (3)-2025-2026学年三年级上册数学人教版
- 2026奥林匹克面试题及答案
- 5-6.项目五 人工智能+智能制造:机器人颜色识别-任务三图像形态学处理与轮廓框选
- 酱油制作工安全操作竞赛考核试卷含答案
- 风机操作工道德竞赛考核试卷含答案
- 电子商务物流配送协议2026年
- 电子商务平台入驻协议(2026年平台交易规则)
- 电商直播客服外包合同协议
- 中国香港脚手架施工方案
- DB43-T 2933-2024 排水降噪沥青路面养护技术规范
- 旭创培训考试题及答案
- 特种设备生产与使用单位质量安全总监及安全员考试题库及答案
- 粮食加工安全培训内容课件
- 国资监管数智化洞察与实践白皮书(发布版)
- 肺康复考试题及答案
- 中科大火灾调查科学讲义03火灾现场勘查
- 四川化材科技有限公司新材料创新孵化基地-高功率光纤激光技术所地联合创新中心环评报告
- 华为基建管理办法
- 沥青混凝土供货方案及保障措施
评论
0/150
提交评论