关闭

关闭

封号提示

内容

首页 彻底搞定C指针_hicode.cn.pdf

彻底搞定C指针_hicode.cn.pdf

彻底搞定C指针_hicode.cn.pdf

上传者: wolaiye777 2011-10-31 评分 5 0 173 24 785 暂无简介 简介 举报

简介:本文档为《彻底搞定C指针_hicode.cnpdf》,可适用于IT/计算机领域,主题内容包含彻彻底底搞搞定定CC指指针针((完完全全版版修修订订增增补补版版))著著==姚姚云云飞飞修修订订==丁丁正正宇宇前言姚云飞先生的大作《彻底搞定C指针符等。

彻彻底底搞搞定定CC指指针针((完完全全版版修修订订增增补补版版))著著==姚姚云云飞飞修修订订==丁丁正正宇宇前言姚云飞先生的大作《彻底搞定C指针》是互联网上中文CC界内为数不多的专门阐述C指针问题的优秀文献资源之一。正如书名所示对于那些学习了C基础知识却始终对C指针不得要领的读者或者那些已经长期被C指针困扰的读者作者致力于彻底解决他们在这方面的难题。为了达到这个目的作者运用了许多生动与亲切的例子深入浅出地讲透了C指针的原理与机制并辅以编程实践中最常用的惯例和技巧作为示范。《彻底搞定C指针》是互联网上下载次数最多的针对C指针问题的中文资源之一。现在经由修订者的重新修订、编辑与排版本书的《完全版修订增补版》全新登场。新版本中的技术用语更加清楚严谨行文的结构层次更加分明例子中的程序代码均通过编译以测试其精准性。修订者希望这份新的成果能够令各位读者在C编程方面获得更多的益处同时也期待着读者们宝贵的反馈信息。再次向姚云飞先生致敬!目录前言目录修订说明A类:规范化B类:更正C类:明晰化D类:编译器第壹篇变量的内存实质.先来理解C语言中变量的实质.赋值给变量.变量在哪里?(即我想知道变量的地址)第贰篇指针是什么?.指针是什么东西第叁篇指针与数组名通过数组名访问数组元素.通过指针访问数组元素.数组名与指针变量的区别.声明指针常量第肆篇constint*pi与int*constpi的区别从constinti说起.constint*pi的语义再看int*constpi.补充三种情况第伍篇函数参数的传递.三道考题函数参数传递方式之一:值传递函数参数传递方式之二:地址传递函数参数传递方式之三:引用传递第陆篇指向另一指针的指针回顾指针概念.指针的地址与指向另一指针地址的指针一个应用实例第柒篇函数名与函数指针通常的函数调用.函数指针变量的声明.通过函数指针变量调用函数.调用函数的其它书写格式.定义某一函数的指针类型函数指针作为某个函数的参数修订说明A类:规范化AC程序的代码段以及行文中的代码的字体均统一调整为CourierNew例如:类型说明符“int”、变量名“a”、地址表达式“a”、函数名“Exchg”等等均作调整。A行为中的代码段按一般行文处理缩进代码段内部规整缩进。A规整C语句例如:语句中形如“a=bc(x,y)”的将调整为形如“a=bc(x,y)”的新样式即在运算符、用来间隔参数的逗号等的旁边补足空白令语句的可读性更强。补全语句结尾的“”。A规整行文语序令其更加通顺。A规整术语写法例如:“C、C”调整为“CC”。B类:更正B更正术语例如:“申明”调整为“声明”。B规整C技术用语例如:“一个声明一整型指针变量的语句”调整为“一条声明一个指向整型变量的指针的语句”。B规整C程序例如:补全定义函数时的类型说明符“void”。补全main()程序段中的“return()”。B规整行文例如:“真正有意义上的指针”调整为“具有真正‘指针’意义的变量”。B更正标点符号例如:将行文里面中文英文标点符号(全角半角)混用、前后抵牾的情况进行更正。将程序里面有编程代码意义的符号(如双引号“"”)中被错误地录入为中文标点符号(全角)的调整为英文(半角)的。B更正一些外语行文。C类:明晰化C初次介绍(不一定是初次出现)专业术语时用黑体字。C需要突出重点的地方用粗体字。C重整程序例如:原作中某处的例中的函数被定义名为“Exchg()”例中的函数被定义名为“Exchg()”那么将例中的函数名在定义中调整为“Exchg()”使它们的逻辑关系更为明晰易于读者阅读和理解。循环体中的“printf("d",ai)”调整为“printf("dn",ai)”。C规整行文分段令其更合乎逻辑。D类:编译器D著者声明相关代码“都是在VC上实验”而修订者则是使用gcc编译器测试相关代码。第壹篇变量的内存实质.先来理解C语言中变量的实质要理解C指针我认为一定要理解C中“变量”的存储实质所以我就从“变量”这个东西开始讲起吧!先来理解理解内存空间吧!请看下图:内存地址||||||||如上图所示内存只不过是一个存放数据的空间就好像我的看电影时的电影院中的座位一样。电影院中的每个座位都要编号而我们的内存要存放各种各样的数据当然我们要知道我们的这些数据存放在什么位置吧!所以内存也要象座位一样进行编号了这就是我们所说的内存编址。座位可以是遵循“一个座位对应一个号码”的原则从“第号”开始编号。而内存则是按一个字节接着一个字节的次序进行编址如上图所示。每个字节都有个编号我们称之为内存地址。好了我说了这么多现在你能理解内存空间这个概念吗?我们继续看看以下的CC语言变量声明:intichara每次我们要使用某变量时都要事先这样声明它它其实是内存中申请了一个名为i的整型变量宽度的空间(DOS下的位编程中其宽度为个字节)和一个名为a的字符型变量宽度的空间(占个字节)。我们又如何来理解变量是如何存在的呢。当我们如下声明变量时:intichara内存中的映象可能如下图:内存地址||||||||变量名|i|a|图中可看出i在内存起始地址为上申请了两个字节的空间(我这里假设了int的宽度为位不同系统中int的宽度可能是不一样的)并命名为i。a在内存地址为上申请了一字节的空间并命名为a。这样我们就有两个不同类型的变量了。.赋值给变量再看下面赋值:i=a=’t’你当然知道个两个语句是将存入i变量的内存空间中将“t”字符存入a变量的内存空间中。我们可以利用这样的形象来理解啦:内存地址||'t'||||||i|a|.变量在哪里?(即我想知道变量的地址)好了接下来我们来看看i是什么意思?是取i变量所在的地址编号嘛!我们可以这样读它:返回i变量的地址编号。你记住了吗?我要在屏幕上显示变量的地址值的话可以写如下代码:printf("x",i)以上图的内存映象为例屏幕上显示的不是i值而是显示i的内存地址编号了。当然在你的实际操作中i变量的地址值不会是这个数了。这就是我所认为的作为初学者应该能够想象到的变量存储的实质了。请这样理解吧!最后总结代码如下:main(){inti=printf(“dn”,i)**printf(“dn”,i)**return()}现在你可知道、两个printf分别在屏幕上输出的是i的什么东西啊好啦!下面我们就开始真正进入指针的学习了。第贰篇指针是什么?.指针是什么东西指针想说弄懂你不容易啊!我们许多初学指针的人都要这样感慨。我常常在思索它为什么呢?其实生活中处处都有指针我们也处处在使用它。有了它我们的生活才更加方便了。没有指针那生活才不方便。不信?你看下面的例子。这是一个生活中的例子:比如说你要我借给你一本书我到了你宿舍但是你人不在宿舍于是我把书放在你的层号的书架上并写了一张纸条放在你的桌上。纸条上写着:你要的书在第层号的书架上。当你回来时看到这张纸条你就知道了我借与你的书放在哪了。你想想看这张纸条的作用纸条本身不是书它上面也没有放着书。那么你又如何知道书的位置呢?因为纸条上写着书的位置嘛!其实这张纸条就是一个指针了。它上面的内容不是书本身而是书的地址你通过纸条这个指针找到了我借给你的这本书。那么我们CC中的指针又是什么呢?请继续跟我来吧下面看一条声明一个指向整型变量的指针的语句:int*pipi是一个指针当然我们知道啦但是这样说你就以为pi一定是个多么特别的东西了。其实它也只过是一个变量而已。与上一篇中说的变量并没有实质的区别。不信你看下面图:内存地址||'t'|||||变量|i|a||pi|(说明:这里我假设了指针只占个字节宽度实际上在位系统中指针的宽度是个字节宽的即位。)由图示中可以看出我们使用“int*pi”声明指针变量其实是在内存的某处声明一个一定宽度的内存空间并把它命名为pi。你能在图中看出pi与前面的i、a变量有什么本质区别吗?没有当然没有!pi也只不过是一个变量而已嘛!那么它又为什么会被称为“指针”?关键是我们要让这个变量所存储的内容是什么。现在我要让pi成为具有真正“指针”意义的变量。请接着看下面语句:pi=i你应该知道i是什么意思吧!再次提醒你啦:这是返回i变量的地址编号。整句的意思就是把i地址的编号赋值给pi也就是你在pi里面写上i的地址编号。结果如下图所示:内存地址||'t'||||变量|i|a||pi|你看执行完pi=i后在图示中的内存中pi的值是。这个就是i变量的地址编号这样pi就指向了变量i了。你看pi与那张纸条有什么区别?pi不就是那张纸条嘛!上面写着i的地址而i就是那个本书。你现在看懂了吗?因此我们就把pi称为指针。所以你要记住指针变量所存的内容就是内存的地址编号!好了现在我们就可以通过这个指针pi来访问到i这个变量了不是吗?看下面语句:printf("d",*pi)那么*pi什么意思呢?你只要这样读它:pi的内容所指的地址的内容(嘻嘻看上去好像在绕口令了)就是pi这张“纸条”上所写的位置上的那本“书”i。你看Pi的内容是也就是说pi指向内存编号为的地址。*pi嘛就是它所指地址的内容即地址编号上的内容了当然就是这个“值”了。所以这条语句会在屏幕上显示。也就是说printf("d",*pi)等价于printf("d",i)请结合上图好好体会吧!各位还有什么疑问?到此为止你掌握了类似i、*pi写法的含义和相关操作吗?总的一句话我们的纸条就是我们的指针同样我们的pi也就是我们的纸条!剩下的就是我们如何应用这张纸条了。最后我给你一道题:程序如下。chara,*paa=pa=a*pa=printf("d",a)你能直接看出输出的结果是什么吗?如果你能我想本篇的目的就达到了。好了就说到这了。HappyStudy!在下篇中我将谈谈“指针的指针”即对int**ppa中ppa的理解。第叁篇指针与数组名通过数组名访问数组元素看下面代码:inti,a={,,,,,,,,,}for(i=i<=i){printf("dn",ai)}很显然它是显示a数组的各元素值。我们还可以这样访问元素如下:inti,a={,,,,,,,,,}for(i=i<=i){printf("dn",*(ai))}它的结果和作用完全一样。.通过指针访问数组元素inti,*pa,a={,,,,,,,,,}pa=a*请注意数组名a直接赋值给指针pa*for(i=i<=i){printf("dn",pai)}很显然它也是显示a数组的各元素值。另外与数组名一样也可如下:inti,*pa,a={,,,,,,,,,}pa=afor(i=i<=i){printf("dn",*(pai))}看pa=a即数组名赋值给指针以及通过数组名、指针对元素的访问形式看它们并没有什么区别从这里可以看出:数组名其实也就是指针。难道它们没有任何区别?有请继续。.数组名与指针变量的区别请看下面的代码:inti,*pa,a={,,,,,,,,,}pa=afor(i=i<=i){printf("dn",*pa)pa*注意这里指针值被修改*}可以看出这段代码也是将数组各元素值输出。不过你把循环体{}中的pa改成a试试。你会发现程序编译出错不能成功。看来指针和数组名还是不同的。其实上面的指针是指针变量而数组名只是一个指针常量。这个代码与上面的代码不同的是指针pa在整个循环中其值是不断递增的即指针值被修改了。数组名是指针常量其值是不能修改的因此不能类似这样操作:a。前面、节中pai*(pai)处指针pa的值是使终没有改变。所以变量指针pa与数组名a可以互换。.声明指针常量再请看下面的代码:inti,a={,,,,,,,,,}int*constpa=a*注意const的位置:不是constint*pa*for(i=i<=i){printf("dn",*pa)pa*注意这里指针值被修改*}这时候的代码能成功编译吗?不能。因为pa指针被定义为常量指针了。这时与数组名a已经没有不同。这更说明了数组名就是常量指针。但是……int*consta={,,,,,,,,,}*不行*inta={,,,,,,,,,}*可以所以初始化数组时必定要这样。*以上都是在VC上实验。LLY箭头本页已使用福昕阅读器进行编辑。福昕软件(C)版权所有仅供试用。第肆篇constint*pi与int*constpi的区别从constinti说起你知道我们声明一个变量时象这样inti这个i是可能在它处重新变赋值的。如下:inti=**i=*这里重新赋值了*不过有一天我的程序可能需要这样一个变量(暂且称它变量)在声明时就赋一个初始值。之后我的程序在其它任何处都不会再去重新对它赋值。那我又应该怎么办呢?用const。**constintic=**ic=*这样是不可以的编译时是无法通过因为我们不能对const修饰的ic重新赋值的。**这样我们的程序就会更早更容易发现问题了。***有了const修饰的ic我们不称它为变量而称符号常量代表着这个数。这就是const的作用。ic是不能在它处重新赋新值了。认识了const作用之后另外我们还要知道格式的写法。有两种:constintic=与intconstic=它们是完全相同的。这一点我们是要清楚。总之你务必要记住const与int哪个写前都不影响语义。有了这个概念后我们来看这两个家伙:constint*pi与intconst*pi按你的逻辑看它们的语义有不同吗?呵呵你只要记住一点:int与const哪个放前哪个放后都是一样的就好比constintic与intconstic一样。也就是说它们是相同的。好了我们现在已经搞定一个“双包胎”的问题。那么int*constpi与前两个语句又有什么不同呢?我下面就来具体分析它们的格式与语义吧!.constint*pi的语义我先来说说constint*pi是什么作用(当然intconst*pi也是一样的前面我们说过它们实际是一样的)。看下面的例子:*代码开始*inti=inti=constint*pi=ipi=i*注意这里pi可以在任意时候重新赋值一个新内存地址*i=*想想看:这里能用*pi=来代替吗?当然不能!*printf("dn",*pi)*输出是**代码结束*语义分析:看出来了没有啊pi的值是可以被修改的。即它可以重新指向另一个地址的但是不能通过*pi来修改i的值。这个规则符合我们前面所讲的逻辑吗?当然符合了!首先const修饰的是整个*pi(注意我写的是*pi而不是pi)。所以*pi是常量是不能被赋值的(虽然pi所指的i是变量不是常量)。其次pi前并没有用const修饰所以pi是指针变量能被赋值重新指向另一内存地址的。你可能会疑问:那我又如何用const来修饰pi呢?其实你注意到int*constpi中const的位置就大概可以明白了。请记住通过格式看语义。哈哈你可能已经看出了规律吧?那下面的一节也就没必要看下去了。不过我还得继续我的战斗!再看int*constpi确实int*constpi与前面的intconst*pi会很容易给混淆的。注意:前面一句的const是写在pi前和*号后的而不是写在*pi前的。很显然它是修饰限定pi的。我先让你看例子:*代码开始*inti=inti=int*constpi=i*pi=i注意这里pi不能再这样重新赋值了即不能再指向另一个新地址。(第行的注释)**所以我已经注释了它。*i=*想想看:这里能用*pi=来代替吗?可以这里可以通过*pi修改i的值。(第行的注释)**请自行与前面一个例子比较。*printf("d",*pi)*输出是**代码结束*语义分析:看了这段代码你明白了什么?有没有发现pi值是不能重新赋值修改了。它只能永远指向初始化时的内存地址了。相反这次你可以通过*pi来修改i的值了。与前一个例子对照一下吧!看以下的两点分析:)pi因为有了const的修饰所以只是一个指针常量:也就是说pi值是不可修改的(即pi不可以重新指向i这个变量了)(请看第行的注释)。)整个*pi的前面没有const的修饰。也就是说*pi是变量而不是常量所以我们可以通过*pi来修改它所指内存i的值(请看第行的注释)。总之一句话这次的pi是一个指向int变量类型数据的指针常量。我最后总结两句:)如果const修饰在*pi前则不能改的是*pi(即不能类似这样:*pi=赋值)而不是指pi。)如果const是直接写在pi前则pi不能改(即不能类似这样:pi=i赋值)。请你务必先记住这两点相信你一定不会再被它们给搞糊了。现在再看这两个声明语句intconst*pi和int*constpi时呵呵你会头昏脑胀还是很轻松惬意?它们各自声明的pi分别能修改什么不能修改什么?再问问自己把你的理解告诉我吧可以发帖也可以发到我的邮箱(我的邮箱yyfcom)!我一定会答复的。.补充三种情况这里我再补充以下三种情况。其实只要上面的语义搞清楚了这三种情况也就已经被包含了。不过作为三种具体的形式我还是简单提一下吧!情况一:int*pi指针指向constinti常量的情况*begin*constinti=int*pipi=i*这样可以吗?不行VC下是编译错。**constint类型的i的地址是不能赋值给指向int类型地址的指针pi的。否则pi岂不是能修改i的值了吗!*pi=(int*)i*这样可以吗?强制类型转换可是C所支持的。**VC下编译通过但是仍不能通过*pi=来修改i的值。去试试吧!看看具体的怎样。**end*情况二:constint*pi指针指向constinti的情况*begin*constinti=constint*piAdministrator高亮Administrator高亮pi=i*两个类型相同可以这样赋值。很显然i的值无论是通过pi还是i都不能修改的。**end*情况三:用constint*constpi声明的指针*begin*inticonstint*constpi=i*你能想象pi能够作什么操作吗?pi值不能改也不能通过pi修改i的值。因为不管是*pi还是pi都是const的。**end*Administrator高亮第伍篇函数参数的传递.三道考题开讲之前我先请你做三道题目。(嘿嘿得先把你的头脑搞昏才行……唉呀谁扔我鸡蛋?)考题一程序代码如下:voidExchg(intx,inty){inttmptmp=xx=yy=tmpprintf("x=d,y=dn",x,y)}main(){inta=,b=Exchg(a,b)printf("a=d,b=dn",a,b)return()}输出的结果为:Administrator高亮x=,y=a=,b=问下划线的部分应是什么请完成。考题二程序代码如下:voidExchg(int*px,int*py){inttmp=*px*px=*py*py=tmpprintf("*px=d,*py=dn",*px,*py)}main(){inta=intb=Exchg(a,b)printf("a=d,b=dn",a,b)return()}输出的结果为为:*px=,*py=a=,b=问下划线的部分应是什么请完成。考题三程序代码如下:voidExchg(intx,inty){inttmp=xx=yy=tmpprintf("x=d,y=dn",x,y)}main(){inta=intb=Exchg(a,b)printf("a=d,b=dn",a,b)return()}输出的结果为:x=,y=a=,b=问下划线的部分应是什么请完成。你不在机子上试能作出来吗?你对你写出的答案有多大的把握?正确的答案想知道吗?(呵呵让我慢慢地告诉你吧!)好废话少说继续我们的探索之旅了。我们都知道:C语言中函数参数的传递有:值传递、地址传递、引用传递这三种形式。题一为值传递题二为地址传递题三为引用传递。不过正是这几种参数传递的形式曾把我给搞得晕头转向。我相信也有很多人与我有同感吧?下面请让我逐个地谈谈这三种传递形式。函数参数传递方式之一:值传递()值传递的一个错误认识先看考题一中Exchg函数的定义:voidExchg(intx,inty)*定义中的x,y变量被称为Exchg函数的形式参数*{inttmptmp=xx=yy=tmpprintf("x=d,y=dn",x,y)}问:你认为这个函数是在做什么呀?答:好像是对参数x、y的值对调吧?请往下看我想利用这个函数来完成对a,b两个变量值的对调程序如下:main(){inta=,b=Exchg(a,b)*a,b变量为Exchg函数的实际参数。*printf("a=d,b=dn”,a,b)return()}我问:Exchg()里头的printf("x=d,y=dn",x,y)语句会输出什么啊?我再问:Exchg()后的printf("a=d,b=dn”,a,b)语句输出的是什么?程序输出的结果是:x=,y=a=,b=为什么不是a=,b=呢?奇怪明明我把a、b分别代入了x、y中并在函数里完成了两个变量值的交换为什么a、b变量值还是没有交换(仍然是a=、b=而不是a=、b=)?如果你也会有这个疑问那是因为你根本就不知实参a、b与形参x、y的关系了。()一个预备的常识为了说明这个问题我先给出一个代码:inta=intxx=ax=x看好了没现在我问你:最终a值是多少x值是多少?(怎么搞的给我这个小儿科的问题。还不简单不就是a=、x=嘛!)在这个代码中你要明白一个东西:虽然a值赋给了x但是a变量并不是x变量哦。我们对x任何的修改都不会改变a变量。呵呵!虽然简单并且一看就理所当然不过可是一个很重要的认识喔。()理解值传递的形式看调用Exch函数的代码:main(){inta=,b=Exchg(a,b)*这里调用了Exchg函数*printf("a=d,b=dn",a,b)}Exchg(a,b)时所完成的操作代码如下所示。intx=a**inty=b*注意这里头两行是调用函数时的隐含操作*inttmptmp=xx=yy=tmp请注意在调用执行Exchg函数的操作中我人为地加上了头两句:intx=ainty=b这是调用函数时的两个隐含动作。它确实存在现在我只不过把它显式地写了出来而已。问题一下就清晰起来啦。(看到这里现在你认为函数里面交换操作的是a、b变量或者只是x、y变量呢?)原来其实函数在调用时是隐含地把实参a、b的值分别赋值给了x、y之后在你写的Exchg函数体内再也没有对a、b进行任何的操作了。交换的只是x、y变量。并不是a、b。当然a、b的值没有改变啦!函数只是把a、b的值通过赋值传递给了x、y函数里头操作的只是x、y的值并不是a、b的值。这就是所谓的参数的值传递了。哈哈终于明白了正是因为它隐含了那两个的赋值操作才让我们产生了前述的迷惑(以为a、b已经代替了x、y对x、y的操作就是对a、b的操作了这是一个错误的观点啊!)。函数参数传递方式之二:地址传递继续!地址传递的问题!看考题二的代码:voidExchg(int*px,int*py){inttmp=*px*px=*py*py=tmpprintf("*px=d,*py=dn",*px,*py)}main(){inta=intb=Exchg(a,b)printf("a=d,b=dn”,a,b)return()}它的输出结果是:*px=,*py=a=,b=看函数的接口部分:Exchg(int*px,int*py)请注意:参数px、py都是指针。再看调用处:Exchg(a,b)它将a的地址(a)代入到pxb的地址(b)代入到py。同上面的值传递一样函数调用时作了两个隐含的操作:将ab的值赋值给了px、py。px=apy=b呵呵!我们发现其实它与值传递并没有什么不同只不过这里是将a、b的地址值传递给了px、py而不是传递的a、b的内容而(请好好地在比较比较啦)整个Exchg函数调用是如下执行的:px=a**py=b*请注意这两行它是调用

类似资料

编辑推荐

[顺风顺水.现代家居办公装修与布局一本通].谢海东.扫描版.pdf

徐光启年谱.pdf

二十四节气饮食养生.pdf

苏轼年谱(下).pdf

对联修辞艺术 王中安.pdf

职业精品

精彩专题

上传我的资料

精选资料

热门资料排行换一换

  • 美学散步-宗白华.pdf

  • 红与黑 --- (法)司汤达.罗…

  • 人类理解论洛克.pdf

  • 士大夫政治演生史稿.pdf

  • 说话心理学++教你如何说漂亮话.…

  • 电动力学(郭硕鸿).pdf

  • ggplot2:数据分析与图形艺…

  • 【梅洛-庞蒂】行为的结构.pdf

  • C语言程序设计(第四版) 谭浩强…

  • 资料评价:

    / 46
    所需积分:2 立即下载

    意见
    反馈

    返回
    顶部