版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本文格式为Word版,下载可任意编辑——C语言指针的用法C语言指针的用法
学习C语言的指针既简朴又好玩。通过指针,可以简化一些C编程任务的执行,还有一些任务,如动态内存调配,没有指针是无法执行的。所以,想要成为一名优秀的C程序员,学习指针是很有必要的。下面是相关的学识,接待阅读。
1关于指针与数组的存储
a、指针和数组在内存中的存储形式
数组p[N]创造时,对应着内存中一个数组空间的调配,其地址和容量在数组生命周期内一般不成变更。数组名p本身是一个常量,即调配数组空间的地址值,这个值在编译时会替换成一个常数,在运行时没有任何内存空间来存储这个值,它和数组长度一起存在于代码中理应是符号表中,在链接时已经制定好了;而指针*p创造时,对应内存中这个指针变量的空间调配,至于这个空间内填什么值即这个指针变量的值是多少,要看它在程序中被如何初始化,这也抉择了指针指向哪一块内存地址。
b、指针和数组的赋值与初始化
根据上文,一般处境下,数组的地址不能修改,内容可以修改;而指针的内容可以修改,指针指向的内容也可以修改,但这之前要为指针初始化。
如:
intp[5];
p=p+1;是不允许的
而p[0]=1;是可以的;
//
int*p;
p=p+1;是允许的
p[0]=1;是不允许的,由于指针没有初始化;
//
inti;
int*p=i;
p[0]=1;是允许的;
对于字符指针还有对比特殊的处境。
如:
char*p=abc;
p[0]=d;是不允许的
为什么初始化了的字符指针不能变更其指向的内容呢?这是由于p指向的是“常量”字符串,字符串abc实际是存储在程序的静态存储区的,因此内容不能变更。这里常量字符串的地址确定在先,将指针指向其在后。
而
charp[]=abc;
p[0]=d;是允许的
这是由于,这个初始化实际上是把常量直接赋值给数组,即写到为数组调配的内存空间。这里数组内存调配在先,赋值在后。
2关于一些表达式的含义
char*p,**p,***p;
charp[],p[][],p[][][];
char*p[],*p[][],**p[],**p[][],**p[],**p[],**p[][];
能明显地知道以上表达式的含义吗?知道的***!
第一组:char*p,**p,***p;
分别为char指针;char*指针,即指向char*类型数据地址的指针;char**指针,即指向char**类型数据的指针;他们都是占4字节空间的指针。
如:
charc=a;
char*p=c;
char**p1=p;
char***p2=p1;
cout***p2endl;p=
其次组:charp[],p[][],p[][][];
分别为一维,二维和三维char型数组,即数组,数组的数组,数组的数组的数组。可以如下的方式举行初始化:
charpp[3]=ab;
charpp1[3][3]=ab;
charpp2[3][3][3]=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,那么实际上是一个指针。下面通过赋值表达式来理解这些表达式的含义:
charc=a;
char*pc=c;
char*p[3],*p1[3][3],**p2[3],**p3[3][3],**p4[3],**p5[3],**p6[3][3],**p7[3];
p[1]=pc;
p1[0][0]=pc;
p2[0]=pc;
p3[0][0]=pc;
*p4[0]=pc;
**p5[0]=c;
**p6[0][0]=c;
**p7[0]=c;
留神,**p7[3]和**p5[3]是等价的。
这里再持续上一小节讲一下数组名给指针赋值的问题。
事实上可以对等赋值的数组和指针关系如下——表示“赋值给”:
数组——指针:p[]——*p
指针的数组——指针的指针:*p[]——**p
指针的指针的数组的——指针的指针的指针:**p[]——***p
。。。。。。
或
数组的数组——数组的指针:p[][]——*p[]
数组的数组的数组的——数组的数组的指针:p[][][]——*p[][]
总之,最外层的数组可以转换指针,往内层不递归。
3关于上述表达式的长度
求一个表达式的“长度”,首先分清表达式实际表示的是一个数组还是一个指针;假设是指针,那么长度为4byte;假设为数组那么要计算实际存储的总元素个数和元素的数据类型。另外要留神要求的是数组元素个数还是数组总字节数;
如:
**p[3][3]
由上文可知上式表示一个指针,因此长度为4byte;而
**p3[3][3]
表示一个二维数组,数组元素类型为指针的指针,因此长度为3*3*4=36;
留神,标准C中sizeof函数求得的是总字节数而非数组长度。
4关于函数的指针返回值和指针参数
指针作为返回值要留神的地方是不要返回局部数据的指针。
如:
char*funvoid
chari=a;
returni;
调用函数fun得不到值a,理由是函数返回后,局部数据在栈中被析构,数据内存被回收,指针指向的数据没有意义;
可以改为:
char*funvoid
chari=a;
char*p=char*malloc5;
Ifp!=NULLp[0]=i,p[1]=\0;
returnp;
这里使用malloc调配了内存在堆中在函数返回后照旧有效。
这里还没完,由于有一天我使用了下面的代码:
char*funvoid
char*p=abc;
returnp;
察觉虽然p定义为局部变量,但返回也是正确的。还记得上面讲到的常量字符串存储位置吗?指针p实际指向了静态数据区,这里的char*p相当于constchar*p,这样的数据在函数返回后是不会被马上回收掉的。
指针作为参数主要用于修改指针指向的数据内容,但修改指针的值无效,
如
char*funchar*p
chari=a;
p=char*malloc5;
p[0]=i;
returnp;
由于传递的是一个指针副本形参指针和实参指针的值一致,但不是同一个指针,不会影响调用方的实参值。诡异的vs2022貌似可以通过形参将实参的值改掉!不过还是不要冒这个险为好了。
5关于const修饰符
const修饰符用于指针时也分外纠结。
首先要分清constchar*p和char*constp。
constchar*p是指向const对象的指针,即对象是只读的,而指针不是。使用const对象的指针要留神两点:
一是不能将其赋值给非const对象的指针,
如:
constchar*p;
char*p1=p;//不允许的
当然,直接使用非const指针指向const对象也是不合法的,
如:
constcharc;
char*p1=c;//不允许的,
这是要制止通过上述p1变更const对象的.值。
二是可以将非const对象的地址赋值给指向const对象的指针,但是试图使用这个指针变更变量的值是非法的,
如:
charc=a;
constchar*p=c;//允许的
*p=b;//不允许的
char*constp是const指针,即指向对象可编辑,但指针本身不成修改,这一点类似于数组。
如:
charc=a;
char*constp=c;
*p=b;//允许的
p++;//不允许的
区分两者的方法是,看const是否靠近指针名,假设是那么为const指针,否那么为const对象。这个助记方法的前提是char要和*号靠在一起,由于constchar*p=charconst*p。
另外,还有constchar*constp,自然是指向const对象的const指针了。
6关于指针函数
首先留神指针函数和函数指针的识别,前者是指“返回指针的函数”,这在上文中有提到,而后者是指“指向函数的指针”。
函数指针的定义方法为,将“函数名”替换为“*函数指针名”,
如:
指向一个声明为voidfuninta的函数指针可以定义为void*pFuninta或void*pFunint,留神这里函数指针pFun只能指向和fun有一致返回类型void和参数类型int的一类函数,另外定义中也不是摆设,去掉会被看做是返回值为void*类型的函数声明。举个例子:
voidfuninta
coutaendl;p=
intmain
void*pFunint;
pFun=fun;//1
*pFun1;//2
事实上,上式中的12行做如下几种替换也是正确的:
a、pFun=fun;
pFun1;
b、pFun=fun;
pFun1;
c、pFun=fun;
*pFun1;
假设有什么疑问的话,可以接着尝试用如下方式直接调用函数fun:
*fun1;
运行的结果也是正确的!这要怎么解释呢?
其实,fun不仅仅作为函数名,它同pFun一样也是一个函数指针,只不过是函数指针常量。为了书写便当,c语言开发者允许将函数指针调用直接写成类似fun的形式,同样函数指针变量赋值也可以写成类似pFun=fun的形式。值得留神的是,函数声明的格式还是对比严格的,如:
voidfunint;//不能写成void*funint。
同样,
void*pFunint;//不能写成voidpFunint。
为了便当,我们还可以定义函数指针类型,针对上述例子的定义方法如下:
typedefvoid*PFUNint;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 傅雷家书读后感(汇编15篇)
- 教育工作者个人先进事迹(9篇)
- 诚信演讲稿合集6篇
- DB12T 443-2011 采暖期室内温度测量方法
- 中秋节活动主持词(6篇)
- 诚信考试承诺书范文集锦5篇
- 新学期工作学习计划4篇范文
- 科技创新:推动绿色交通与城市规划绿色融合
- 明星课件教学课件
- 文书模板-未履行合同义务索赔函
- 市政工程变更流程资料表格附件
- 课程设计——夹套反应釜
- 调节池施工方案范文
- 专项施工方案编制依据
- 正比例函数的图象与性质说课稿
- 施工单位履约后评价报告(共2页)
- 《生活中的度量衡》PPT课件.ppt
- 趣味数学推理小故事PPT精品文档
- Excel支票打印模板2021
- 《危险游戏莫玩耍》PPT课件.ppt
- 自-铣削用量进给量进给速度(精编版)
评论
0/150
提交评论