ImageVerifierCode 换一换
格式:DOCX , 页数:52 ,大小:98.68KB ,
资源ID:21352264      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/21352264.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(C程序设计语言5Word文档格式.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

C程序设计语言5Word文档格式.docx

1、Y、=*ip;*ip=0;ip=z【0】;ip现在指向x +y的值现在为l +x的值现在为0 4ip现在指向Z0 4 变量x、Y与Z的声明方式我们已经在前面的章节中见到过。我们来看指针ip的声明,如 下所示: int 这样声明是为了便于记忆。该声明语句表明表达式*ip的结果是int类型。这种声明变量的语 法与声明该变量所在表达式的语法类似。同样的原因,对函数的声明也可以采用这种方式。 例如,声明 double*dp,atof(char); 表明,在表达式中,*dp和atof(S)的值都是double类型,J王atof的参数是一个指向char 类型的指针。 我们应该注意,指针只能指向某种特定类型

2、的对象,也就是说,每个指针都必须指向某 种特定的数据类型。(一个例外情况是指向v。id类型的指针可以存放指向任何类型的指针, 但它不能间接引用其自身。我们将在511节中详细讨论该问题)。 如果指针ip指向整型变量x,那么在x可以出现的任何上下文中都可以使用4ip,因此, 语句 。 *ip;*ip+10; 将把*ip的值增iJIl0。 一元运算符木和&的优先级比算术运算符的优先级高,因此,赋值语句 Y 2*ip+1 、 将把*ip指向的对象的值取出并加l,然后再将结果赋值给Y,而下列赋值语句: *ip+=1回 则将ip指向的对象的值加l,它等同于 +ip 或(*ip)+语句的执行结果。语句(术i

3、D)十+中的圆括号是必益的,否则,该表达式将对ip进行加二运算,而不是塑ip指向的对象进行地二蓝算,这是因为,类似于术和+这样的一元运算符遵循从右l指针与数纽至左的结合顺序。 最后说明一点,由于指针也是变量,所以在程序中可以直接使用,而不必通过间接引用的方法使用。例如,如果iq是另一个指向整型的指针,那么语句 iq=ip将把ip中的值拷贝到iq中,这样,指针iq也将指向ip指向的对象。52指针与函数参数 由于9蔓盖星丛传值的方煎!睦数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量的值。例如,排序函数可能会使用二个名为swap的函数来交换两个次序颠倒的元素。但是,如果将swap函

4、数定义为下列形式: 厂 九 ivoid swap(int X。int Y),4 错误定义的函数+ J T 、 int temp:temp=X;X 2 Y;Y。temp;则下列语句无法达到该目的。swap(a,b);这是因为,由于参数传递采用传值方式,因此上述的swap函数不会影响到调用它的例程中的参数a和b的值。该函数这堡交换了a和b的副本的值。 , 0-o-_-o_l-_00-0_-_-_-一 那么,如何实现我们的目标呢?可以使主调程序将指向所要交换的变量的指针传递给被调用函数,即: swap Ca。b);由于一元运算符&用来取变量的地址,这样&a就是一个指向变量a的指针。swap函数的所有

5、参数都声明为指针,并且通过这些指针来间接访问它们指向的操作数。眄习卜、-、lVoid swap(int*px。py1 + 交换+px和4PY + 。1。一 $nt temp; temp。*px; px。PY: *Py。temp: 我们通过图52进行说明。 塑针参数使堡垫塑盥数能够访问和修改主诅函数中对象的值。我们来看这样一个例子:函数9etint接受自由格式的输入,并执行转换,将输入的字符流分解成整数,且每次调用得到一个整数。9etint需要返回转换后得到的整数,并且,在到达输入结尾时要返回文件结标记。这些值必须通过不同的方式返回。EOF(文件结束标记)可以用任何值表示,当然也可用一个输入的整

6、数表示。 在主调函数中:在 图52 可以这样设计该函数:将标识是否到达文件结尾的状态作为9etint函数的返回值,同时, 使用一个指针参数存储转换后得到的整数并传回给主调函数。函数scanf的实现就采用了这 种方法,具体细节请参见74节。 下面的循环语句调用getint函数给一个整型数组赋值: int narraySIZE。getint(int) , for In t 0:nSIZE&getint(&arrayn)1;EOF;n+J ; 每次调用9etint时,输入流中的下一个整数将被赋值给数组元素array【n,同时,n的值 将增加1。请注意,这里必须将arrayn的地址传递给函数9etin

7、t,否则函数getint将 无法把转换得到的整数传回给调用者。 该版本的9etint函数在到达文件结尾时返回EoF,当下一个输入不是数字时返回0,当陌习 输入中包含一个有意义的数字时返回一个正值。#includeint getch(void);void ungetch(int):+ getint函数:将输入中的下一个整型数赋值给+pn +int getint(intpn) int c。sign; whileI(cgeteh()+跳过空白符4 if(1isdiglt(c)&c l_EOF_&c l-+矗e It) ungetch(c); + 输入不是一个数字 + return 0; J指针与教纽

8、 ) sign t(c t一-)71:1: if(c一+:c t-一) c。getch(); for(*pn-0;isdiglt(c);c t getch() pn_10-pn+(c一0); *pnt sign: if(c I=EOF) return C; 在g e t i n t函数中,幸pn始终作为一个普通的整型变量使用。其中还使用了9 e t c h和ungetch两个函数(参见43节),借助这两个函数,函数getint必须读人的一个多余字符就可以重新写回到输入中。 练U5-1 在上面的例子中,如果符号+或一的后面紧跟的不是数字,getint函数将把符号视为数字0的有效表达方式。修改该函

9、数,将这种形式的+或一符号重新写回到输入流中。 练习5-2 模仿函数9etint的实现方法,编写一个读取浮点数的函数9etfloat。getfloat函数的返回值应该是什么类型?53指针与数组 在c语言中,指针和数组之间的关系十分密切,因此,在接下来的部分中,我们将同时讨论指针与数组。通过数组下标所能完成的任何操作都可以通过指针来实现。一般来说,用指针编写的程序比用数组下标编写的程序执行速度快,但另一方面,用指针实现的程序理解起来稍微困难一些。臣口 声明 Int“10】;定义了一个长度为l0的数组a。换句话说,它定义了一个由10个对象组成的集合,这l0个对象存储在相邻的内存区域中,名字分别为a

10、0、a1、a9(参见图53)。 a:工二工丁卫 【O】【1】 -【9】 图53ai表示该数组的第i个元素。如果pa的声明为 int*pa;则说明它是一个指向整型对象的指针,那么,赋值语句 pa-“0】; 则可以将指针pa指向数组a的第0个元素,也就是说,pa的值为数组元素a0的地址(参见图54)。这样,赋值语句 x_pa;pa:a【0】图54将把数组元素a0中的内容复制到变量X中。 如果pa指向数组中的某个特定元素,那么,根据指针运算的定义,pa+1将指向下l个 、-,一-。、蓝pa+i将指向pa所指向数组元素之后的第i个霾素,而pai将指向pa所指向数组元素之前的第i个元素。因此,如果指针p

11、a指向a0,那么木(pa+1)引用的是数组元素a1的内容,pa+i是数组元素ai的地址,术(pad)引用的是数组元素ai幽容(参见图55)。图55 无论数组a中元素的类型或数组长度是什么,上面的结论都成立。“指针加l”就意味着, pa+1指向pa所指向的对象的下一个对象。相应地,pa+i指向pa所指向的对象之后的第i个乜纠 对象。 c 。 下标和指针运算之间具有密切的对应关系。根据定义,数组类型的变量或表达式的值是 该数组第0个元素的地址。执行赋值语句 pa薯&a【0】; 后,pa和a具有相同的值。因为数组名所代表的就是该数组最开始的一个元素的地址,所以, 赋值语句pa=&a0也可以写成下列形

12、式: pa=a; 对数组元素ai的引用也可以写成半(a+i)这种形式。对第一次接触这种写法的人来说, 可能会觉得很奇怪。在计算数组元素ai的值时,C语言实际上先将其转换为t(a+i)的形式, 然后再进行求值,因此在程序中这两种形式是等价的。如果对这两种等价的表示形式分别施 加地址运算符&,便可以得出这样的结论:ai和a+i的含义也是相同的。a+i是a之后第i指针s数组个元素的地址。相应地,如果pa是一个指针,那么,在表达式中也可以在它的后面加下标。3ai与t(pa+i)是等价的。简而言之,一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现。 但是,我们必须记住,数组名和指针之间有一个不

13、同之处。指针是一个变量,因此,在C浯言中,语句pa=a和pa+都是合法的。但数组名不是变量,因此,类似于a=pa和a+形式的语句是非法的。 当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。在被调用函数中,该参数是一个局部变量,因此,数组名参数必须是一个指针,也就是一个存储地址值的变量。我们可以利用该特性编写strlen函数的另一个版本,该函数用于计算一个字符串的长度。4 Strlen函数:返回字符串S的长度 +int strlen(chars) int n; for In昌0; s I= 0; s+) n+; return n;因为S是一个指针,所以对其执行自增运算是合法的。

14、执行S+运算不会影响到Strlen函数的调用者中的字符串,它仅对该指针在Strlen函数中的私有副本进行自增运算。因此,、类似于下面这样的函数调用: 7strlen(”hell0,world”); 4 字符串常量+strlen(array): 4 字符数组array有1 0 0个元素 +strlen(ptr); +ptr是一个指向char类型对象的指针 +部可以正确地执行。 在函数定义中,形式参数 char 8【】;和是等价的。我们通常更习惯于使用后一种形式,因为它比前者更直观地表明了该参数是一个指针。如果将数组名传递给函数,函数可以根据情况判定是按照数组处理还是按照指针处理,随后根据相应的方

15、式操作该参数。为了直观且恰当地描述函数,在函数中甚至可以同时使用故组和指针这两种表示方法。 也可以将指向子数组起始位置的指针传递给函数,这样,就将数组的一部分传递给了函牧。例如,如果a是一个数组,那么下面两个函数调用 fla【2】)与圈 f(a+2) 7都将把起始于a2的子数组的地址传递给函数f。在函数f中,参数的声明形式可以为 f(int aEE【】)或 f(int*aEr),对于函数f来说,它并不关心所引用的是否只是一个更大数组的部分元素。 如果确信相应的元素存在,也可以通过下标访问数组第一个元素之前的元素。类似于P【-1、P卜2这样的表达式在语法上都是合法的,它们分别引用位于p0之前的两

16、个元素。当然,引用数组边界之外的对象是非法的。54地址算术运算 如果P是一个指向数组中某个元素的指针,那么P+将对P进行自增运算并指向下一个元 素,而p+=i将对P进行加i的增量运算,使其指向指针P当前所指向的元素之后的第i个元素。 这类运算是指针或地址算术运算中最简单的形式。 C语言中的地址算术运算方法是一致且有规律的,将指针、数组和地址的算术运算集成在 一起是该语言的一大优点。为了说明这一点,我们来看一个不完善的存储分配程序。它由两 个函数组成。第一个函数alloc(n)返回一个指向n个连续字符存储单元的指针,alloc函数 的调用者可利用该指针存储字符序列。第二个函数afree(P)释放

17、已分配的存储空间,以便 以后重用。之所以说这两个函数是“不完善的”,是因为对afree函数的调用次序必须与调用1100l allOC函数的次序相反。换句话说,alloc与afree以栈的方式(即后进先出的列表)进行 存储空间的管理。标准库中提供了具有类似功能的函数malloc和free,它们没有上述限制, 我们将在87节中说明如何实现这些函数。 最容易的实现方法是让allOC函数对一个大字符数组allocbuf中的空间进行分配。该 数组是allOC和afree两个函数私有的数组。由于函数alloc和afree处理的对象是指针而 不是数组下标,因此,其他函数无需知道该数组的名字,这样,可以在包含

18、alloc和afree 的源文件中将该数组声明为StatiC类型,使得它对外不可见。实际实现时,该数组甚至可以 没有名字,它可以通过调用malloc函数或向操作系统申请一个指向无名存储块的指针获得。 a110Cbuf中的空间使用状况也是我们需要-解的信息。我们使用指针allocp指向 a1 1 0 Cbu f中的下一个空闲单元。当调用a l l 0 C申请n个字符的空间时,a l l 0 C检查 allocbuf数组中有没有足够的剩余空间。如果有足够的空闲空间,贝ralloc返回allocp的 当前值(即空闲块的开始位置),然后将al locp力In以使它指向下一个空闲区域。如果空闲 空间不够

19、,则all0C返回0。如果P在a110cbuf的边界之内,则afree(P)仅仅只是将 allocp的值设置为P(参见图56)。 #define ALLOCSIZE l0000+ 可用空间大小 4static char allocbufALLOCSIZE: + alloc使用的存储区+static charallocp 2 a110cbuf; + 下一个空闲位置 4char*alloc(int n) + 返回指向n个字符的指针 + if(allocbuf+ALLOCSIZEallocp)-2 n)+ 有足够的空闲空间 + allocp+窜n: return allocpn;4 分配前的指针p

20、8 )else + 空闲空间不够 +void afree(charp) + 释放P指向的存储区 + if(p=allocbuf&pallocbuf+ALLOCSIZE) allocp。p;调用allOC之前: allocp: almbur:工二口二二二二二二二 _已使用_+_ 空闲一调用allOC之后:all。cbur:二口二二二二二二 _ 已使用H_空闲一图56 一般情况下,同其他类型的变量一样,指针也可以初始化。通常,对指针有意义的初始七值只能是0或者是表示地址的表达式,对后者来说,表达式所代表的地址必须是在此前已定泛的具有适当类型的数据的地址。例如,声明 static char*allo

21、cp 2 allocbuf;辱allocp定义为字符类型指针,并将它初始化为allocbuf的起始地址,该起始地址是程序jl【行时的下一个空闲位置。上述语句也可以写成下列形式: static char*allocp 2&allocbuf0】;茎是因为该数组名实际上就是数组第0个元素的地址。 下列if测试语句: if(allocbuf+ALLOCSIZEallocp=n)+ 有足够的空闲空间 +釜查是否有足够的空闲空间以满足n个字符的存储空间请求。如果空闲空间足够,则分配存储!间后al l ocp的新值至多比al l ocbuf的尾端地址大l。如果存储空间的申请可以满足,lloc将返回一个指向所

22、需大小的字符块首地址的指针(注意函数本身的声明)。如果申请无满足,allOC必须返回某种形式的信号以说明没有足够的空闲空间可供分配。语言保证,永远不是有效的数据地址,因此,返回值0可用来表示发生了异常事件。在本例中,返回值D回表示没有足够的空闲空间可供分配。 指针与整数之间不能相互转换,但O是惟一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中经常用符号常量NULL代替常量0,这样便于更清晰地说明常量0是指针的一个特殊值。符号常量NuLL定义在标准头文件中。我们在后面部分经常会用NNULL。 类似于 if(allocbuf+ALLOCSIZEallocpz n)4有足够的空闲空

23、间+ 以及 if(P=a110cbufPallocbuf+ALLOCSIZE) 的条件测试语句表明指针算术运算有以下几个重要特点。首先,在某些情况下对指针可以进 行比较运算。例如,如果指针p和q指向同一个数组的成员,那么它们之间就可以进行类似于 =、!=、=的关系比较运算。如果P指向的数组元素的位置在q指向的数组元素位置之前, 那么关系表达式 Pq匝圈 的值为真(true)。任何指针与0R行相等或不等的比较运算都有意义。但是,指向不同数组 的元素的指针之间的算术或比较运算没有定义。(这里有一个特例:指针的算术运算中可使用 数组最后一个元素的下一个元素的地址。) 其次,我们从前面可以看到,指针可

24、以和整数进行相加或相减运算。例如,结构 P+n 表示指针P当前指向的对象之后第n个对象的地址。无论指针P指向的对象是何种类型,上述 结论都成立。在计算p+n时,lq将根据p指向的对象的长度按比例缩放,而b指向的对象的长度 则取决于p的声明。例如,如果int类型占4个字节的存储空间,那么在int类型的计算中, 对应的n将按4的倍数来计算。 指针的减法运算也是有意义的:如果P和q指向相同数组中的元素,且Pq,那么qp+l 就是位于P和q指向的元素之间的元素的数目。我们由此可以编写出函数strlen的另一个版 本,如下所示: + Strlen函数:返回字符串S的长度 + t int strlen(c

25、harB) charp=S: while(p l=0) p+; return P一8:在上述程序段的声明中,指针P被初始化为指向S,即指向该字符串的第一个字符。whileN环语句将依次检查字符串中的每个字符,直到遇到标识字符数组结尾的字符0为止。由于P是指向字符的指针,所以每执行一次p+,P就将指向下一个字符的地址,PS则表示已经检查过的字符数,即字符串的长度。(字符串中的字符数有可能超过int类型所能表示的最大范围。头文件中定义的类型ptrdiff_t足以表示两个指针之间的带符号差值。但是,我们在这里使用SiZe,t作为函数Strlen的返回值类型,这样可以与标准库中的函数版本相匹配。SiZ

26、e_t是由运算符Sizeof返回的无符号整型。 指针的算术运算具有一致性:如果处理的数据类型是比字符型占据更多存储空间的浮点类型,并且P是一个指向浮点类型的指针,那么在执细+后,P将指向下一个浮点数的地址。因此,只需要将alloc和afree函数中所有的char类型替换为float类型,就可以得到一个适用于浮点类型而非字符型的内存分配函数。所有的指针运算都会自动考虑它所指向的对象的长度。 有效的指针运算包括相同类型指针之间的赋值运算;指针同整数之间的加法或减法运茸;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或指针与0之间的比较运算。其他所有形式的指针运算都是非法的,例如两个指针间的加法、乘法、除法、移直或屏蔽运算;指针同float或double类型之间的加法运算;不经强制类型转换而直接

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1