C语言高级mac os x编程 pdf:x³-a=0的高级mac os x编程 pdf

君,已阅读到文档的结尾了呢~~
高级超经典c语言编程题目高级,习题,编程,C语言编程,题经典,经典编程,高级编程,C语言题目,超经典,编程语言
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
高级超经典c语言编程题目
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口写教程,改变世界
作者:远山
标签:编程,入门
有效阅读:267
点击量:5143
免责声明:本站(guideep)之内的所有教程概由作者自由创作并承担全部责任。教程的内容和观点未经 guideep 审核。读者在阅读过程中应自行鉴别其是否真确、有效或安全。特别地,如果教程内容涉及化学、生物、高压电气、放射性、医疗、气功、宗教、运动等可能造成严重后果的领域,请读者慎重鉴别,切勿盲目学习。本站不对学习造成的后果承担任何责任。
编程起步教程
[div=#ffffcc][color=red]基础要求[/color]:本教程面向对编程一无所知的门外汉,从零开始介绍编程的基本概念,快速提供对编程活动的全景式概览。
本教程不教授某种特定语言的编程方法。[/div]
[toggle=off]
[title]一、基本概念[/title]
[content]编程就是编写程序。
那么什么是程序?我们先说教程。在 guideep 和 guideep 以外,你一定看过很多教程了。你想做一件事,但不知怎么做,看过教程才会做。
所以,教程是用来指导人如何去做一件事的资料。
如果有一些特殊的教程,它指导的对象不是人,而是[toggle=off]
[title]计算机[/title]
[content]本教程中提到的计算机,包含各种具有计算能力的设备,如桌面电脑、手机、平板、手表、家电、智能硬件,以及专业领域所用的小型、大型、巨型计算机等。上述所有计算机都需要编程。[/content][/toggle],它能告诉计算机如何去做一件事,这种教程就是[b]程序[/b][a=program]。
因此,编程就是指导计算机去做事。计算机做任何事都需要依照程序去做。
由于计算机暂时难以有效理解人类使用的自然语言,要指导它做事必须使用它的语言,这就是[goto=proglang]编程语言[/goto]。
从[goto=huibian]汇编语言[/goto]开始[toggle=off]
[title][sup][注][/sup][/title]
[content]代码,就是代替二进制编码之意。[goto=machinelang]机器语言[/goto]本身是二进制编码,故不称代码。[/content][/toggle],在程序之内的语句也叫[b]代码[/b][a=code]。所以程序是由代码组成的,犹如文章是由文句组成的。
还有一个概念是[b]软件[/b][a=software]。软件与程序在很大程度上能够通用,只是表达的侧重点有所不同。程序强调生产属性,是产品;软件强调销售属性,是商品。
[/content][/toggle]
[toggle=off]
[title]二、编程语言[/title]
[content][a=proglang]在计算机领域里所说的语言一般有两种:[b]标记语言[/b]和[b]编程语言[/b]。前者是指像 [wiki=zh]HTML[/wiki]、[wiki=zh]XML[/wiki] 一类,用标签修饰文本,使文本具有一定的结构或显示出特定的静态效果。它们的功能是静态的,不能执行计算任务。
下面我们提到的“语言”都是指编程语言。
计算机真正能够理解的语言只有一种,这就是[b]机器语言[/b]。用其它语言书写的程序必须[toggle=off]
[title]翻译成机器语言[/title]
[content]当然,这个翻译过程也需要用程序来实现。[/content][/toggle],才能让计算机读懂。这种翻译过程分两种:[b]编译[/b]和[b]解释[/b]。
数十年来,人们创造了不计其数的编程语言,其中比较重要的有以下几种:
[toggle=off]
[title]机器语言[/title]
[content][a=machinelang]计算机真正能理解的只有一种内容,就是由数字 1 和 0 组成了[wiki=zh]二进制[/wiki]数字流。机器语言就是用这种形式呈现的。例如:
[div][a=bits]1010……[/div]
在计算机刚刚诞生的年月,人们把这样的数字流[toggle=off]
[title]打在纸带上[/title]
[content]不是打印,而是在一根窄长的纸带上打上许多小孔,用孔的位置表示输入的数字。[/content][/toggle],输入计算机,计算机再把计算结果打在另一根纸带上输出给人。
将人的思维与纸带上的小孔来回转换是非常痛苦的事。幸好,后来有了用于输入的键盘和用于输出的显示器。
机器语言看上去是没完没了的一长串,实际它可以断成多条语句,各自指示一个步骤。对于断句的原则,不同的计算机各有不同,而步骤的含义却是大同小异。例如,要计算 ( 34+7 ) * 6,大概需要这样几步:
[div]1、把 34 这个数放在某个寄存器[toggle=off]
[title][sup][?][/sup][/title]
[content]寄存器是计算机硬件的一种设备,用于快速存放一些临时数据。详见维基:[wiki=zh]寄存器[/wiki]。[/content][/toggle]里;
2、对上述寄存器里的数加 7;
3、对上述寄存器里的数乘 6;[/div]
这就是前面[goto=bits]那一串 0101[/goto] 表达的信息。值得注意的是,在上述每个步骤中都含有一个指令(放、加、乘),指令之外也可能有一些数据(34、7、6),也可能没有数据。命令和数据都以二进制串表示。计算机照此执行,寄存器里就得到我们想要的计算结果了。
后来的程序员基本不再需要使用机器语言,因为它的替代品——[goto=huibian]汇编语言[/goto]出现了。
[/content][/toggle]
[toggle=off]
[title]汇编语言[/title]
[content][a=huibian]汇编语言对机器语言提供了一个人类可读的版本。首先,将机器语言的一长串数字断成一句一句,再把每一句中的指令部分由数字改写为字母,数据部分由二进制改为[wiki=zh]十进制[/wiki],更符合人类的阅读习惯。例如,上面的算式 ( 34+7 ) * 6,用汇编语言写出来大概是这样:
[div]MOV AX 34&&& ;[color=blue]MOV 指令就是把某个数放在某个位置,AX 是寄存器。[/color]
ADD AX 7&&& ;[color=blue]ADD 指令是相加。[/color]
MUL AX 6&&& ;[color=blue]MUL 指令是相乘。[/color][/div]
注意,在上面每行代码的分号(;)之后直到行末,各有一段对这一行代码的说明(蓝字),这叫[b]注释[/b][a=remark]。注释是纯粹写给人看的,计算机阅读代码时会忽略注释。汇编语言用分号作行内注释的分隔符,其它语言有用双斜线(//)的[toggle=off]
[title][sup][例][/sup][/title]
[content]C++、Java、Javascript 等。[/content][/toggle],有用井号(#)的[toggle=off]
[title][sup][例][/sup][/title]
[content]Python 等。[/content][/toggle],也有用大括号({})[toggle=off]
[title][sup][例][/sup][/title]
[content]Pascal 等。[/content][/toggle]或其它符号(/*& */)[toggle=off]
[title][sup][例][/sup][/title]
[content]C、C++、Java、Javascript 等。[/content][/toggle]将多行注释内容括起来的。
汇编语言的每条语句与机器语言等价,因此它的执行速度也像机器语言一样快,可是要做一件事,需要的代码量往往很大。例如前面算个 ( 34+7 ) * 6,就需要三行代码,编程效率相当低下。后来,人们为了提高效率,创造了一系列高级语言,用一行代码起到汇编语言的多行代码的作用。高级语言不需要理会寄存器了,以下介绍的就是这些高级语言。
高级语言的编程效率远远超过汇编语言,执行速度却没有汇编语言快。但随着技术进步,两者执行速度之间的差异正在缩小,C 语言与等效汇编语言之间执行速度的差异已经降到 20% 以内,再加上硬件性能的快速提高,真正需要汇编语言的领域已经越来越窄,只有最底层的硬件驱动仍然需要汇编语言。
[/content][/toggle]
[toggle=off]
[title]C 语言[/title]
[content][a=c]若要评选一种最重要的编程语言,没有之一,那一定非 C 莫属。
C 的执行速度相当快,适用于开发[wiki=zh]操作系统[/wiki]和硬件驱动。而灵活的功能和强大的表现力也使之成为各种应用软件的雀屏之选。C 成了过去三十年里最流行的编程语言,不仅著名的操作系统 UNIX 和 Linux 等用 C 写成,连各种算法的教程也大多通过 C 语言讲授。
在本教程中,我们也将以 C 为例介绍一些编程中的概念。
在2014年4月最流行的编程语言排行榜上,前五名依次是:
3、Objective-C
5、C#[/div]
C 不但高居榜首,而且从第三、四、五名的名字也不难看出它们与 C 之间的密切关系。即使第二名 Java 的名字里没有 C,其语法仍然受到 C 的深刻影响。
[/content][/toggle]
[toggle=off]
[title]Lisp 语言[/title]
[content][a=lisp]在 Lisp 界有句名言——Lisp 是程序员需要学习的最后一种语言。
Lisp 比 C 更古老,但它的流行程度一直不高。可是,独树一帜的抽象能力和高度的灵活性使之在编程语言中占据了不可或缺的重要地位。
Lisp 是最早的[goto=hanshushi]函数式编程[/goto]语言,区别于 C/Java 等命令型编程语言。Lisp 也是第一种支持[goto=digui]递归[/goto]的高级语言。
Lisp 以独特的 s 表达式构成代码,看上去更像是数学,或者思想。可能是这种过于抽象的写法挡住了用户。新的编程语言层出不穷,越来越抽象,越来越高效(指编程效率,不是执行效率),也越来越像 Lisp。
延伸阅读:[url=/blog/2010/10/why_lisp_is_superior.html]为什么Lisp语言如此先进?[/url]
[/content][/toggle]
[toggle=off]
[title]C++ 语言[/title]
[content][a=cpp]C++ 是 [goto=c]C 语言[/goto]的升级版,最重要的是添加了[goto=oo]面向对象[/goto]功能,后来又陆续引入了虚函数、运算符重载、多重继承、模板、异常处理、RTTI、命名空间等特性。这使得 C++ 强大而复杂,难用易错。甚至有人认为,谁都不可能掌握 C++ 的所有功能。
微软公司的一系列产品如 [wiki=zh]windows[/wiki]、[wiki=zh]office[/wiki] 等都使用 C++ 开发。
[/content][/toggle]
[toggle=off]
[title]Java 语言[/title]
[content]Java 像是一种简化的 [goto=cpp]C++[/goto],去掉了 C++ 中的指针、多重继承、运算符重载等特性,并限制使用纯粹面向对象的开发模式。看上去比 C++ 简单、规范而安全,易于掌握。
但真正令 Java 能在排行榜上与 C 一较高下的是其优异的跨平台特性。C 的编译是直接转成汇编语言,而 Java 是编译成字节码,字节码在 Java 虚拟机(JVM)上运行。不同的硬件平台各自提供 JVM,可以运行相同的字节码。这意味着,用 Java 写出的程序可以不考虑硬件平台,到处适用。
JVM 的魅力似乎比 Java 语言本身更大。一些其它语言也纷纷出现了运行在 JVM 上的版本,如 [goto=python]Python[/goto] 有 Jython,Ruby 有 JRuby,[goto=lisp]Lisp[/goto] 有 Clojure。
[/content][/toggle]
[toggle=off]
[title]Javascript 语言[/title]
[content][a=js]不要被它的名字误导,Javascript (js)与 Java 的关系,比 C++ 与 C 的关系可疏远得太多了,疏远到几乎没有关系。js 是一种相当独特的语言,它的另一个名字 ECMAScript 看上去更不易引起误解。
js 是一种基于原型的语言,这是面向对象的一种特殊形式,与 C++ 或 Java 的实现方法大不相同。
如果你从未学习过任何编程语言,想要选择一种语言从头开始学习编程,我会推荐 js 给你。
理由有二:1、js 可以在浏览器中运行,免去了搭建开发环境的麻烦。2、大多数程序员多少都会懂一点 js,即便 js 不是他主要使用的语言。因此,你更容易获得帮助。
虽然也能用在服务端[toggle=off]
[title][sup][注][/sup][/title]
[content]Node.js 是个很有前途的服务端开发工具。在微软的 [wiki=zh]ASP[/wiki] 里,也可用 js 语言代替默认的 [wiki=zh]VBscript[/wiki]。[/content][/toggle],js 最大的用途始终是在浏览器中为网页提供动态能力[toggle=off]
[title][sup][例][/sup][/title]
[content]例如你刚刚点开的这个隐现控件,再一点就收拢,类似的动态效果都是用 js 实现的。[/content][/toggle],在浏览器里,js 几乎一统天下。
[/content][/toggle]
[toggle=off]
[title]PHP 语言[/title]
[content]与 [goto=js]Javascript[/goto] 相反,PHP 是一个用在 web 服务端[toggle=off]
[title][sup][注][/sup][/title]
[content]在 web(就是你用浏览器打开的网站)开发中,我们把在网站服务器上执行的工作称为服务端,或者后端;把在访问者浏览器上执行的工作称为客户端,或者前端。
[/content][/toggle]的语言。PHP 可以嵌入 HTML 之中,向前端提供动态的数据。
PHP 的使用范围一度相当广泛。在中小型网站常用的[toggle=off]
[title] LAMP [/title]
[content]LAMP,四个字母分别指 [wiki=zh]Linux[/wiki](操作系统)、[wiki=zh]Apache[/wiki](web 服务器)、[wiki=zh]MySQL[/wiki](数据库)、PHP(服务端编程语言)。[/content][/toggle]套件中的 P 就是指 PHP。中国大陆常见的论坛系统,如 Discuz!、phpwind 等都是用 PHP 开发的。
[/content][/toggle]
[toggle=off]
[title]Python 语言[/title]
[content][a=python]Life is short, you need Python.
与 Lisp 相似,Python 具有高度的抽象能力和高度的灵活性,因而具有极高的编程效率。一名 Python 程序员所能完成的工作,如果改用 C 或 Java 来做,可能需要一个团队。而 Python 的语句却又具有上佳的可读性,不像 Lisp 那样怪异[toggle=off]
[title][sup][及][/sup][/title]
[content]有个笑话,说前苏联间谍偷到了美国控制导弹发射的 Lisp 程序的最后两页,拿回去一看,满满的两页全是右括号。
[/content][/toggle]。
易学、易用、易读、易调试而且功能强大,使 Python 在 web 后端、云计算、科学计算等领域大获成功,成为一种重要的语言。
Python 是 [wiki=zh]GAE[/wiki] 支持的第一种语言。Google 大量使用 Python。Dropbox、BitTorrent、Quora、豆瓣、果壳、知乎等网站及许多 APP 也是用 Python 构建的。
在本教程中,将使用 Python 展示一些编程特性。
Python 的主要缺点是运行速度较慢。CPython(用 C 写的 Python 解释器)上的执行时间大概比 C 语言写出的等价程序多用几十倍,比 Java 也慢一些。目前有一些旨在提高 Python 运行效率的项目,其中,据称 PyPy(用 Python 写的 Python 解释器)比 C 的效率仅差 20% 左右。
[/content][/toggle]
[toggle=off]
[title]新语言[/title]
[content]在近几年新出的语言中,似乎以 Google 的 GO 语言和苹果的 Swift 语言最受关注。
[/content][/toggle]
[/content][/toggle]
[toggle=off]
[title]三、程序特性[/title]
[content]前面介绍的高级语言中,除 Lisp 之外,其它几种的语法都有很大的共通之处。在本节中,我们用一些最简单的代码片段展示一些程序特性。读者应着重掌握每一特性的思想,不必过于关注代码的写法。
[toggle=off]
[title]分支[/title]
[content][a=if][b]分支[/b]是在程序运行中,选择执行或跳过某些代码的行为,一般用 if - else 语句实现。[goto=c]C[/goto] 代码如下[toggle=off]
[title][sup][注][/sup][/title]
[content]这是高度简化的代码。真正的 C 代码中,要把这一段写在[goto=func]函数[/goto]里,从 main 函数调用,x 和 y 都必须声明。
[/content][/toggle]:
[div=#ffffcc]if( x & 3 )[a=code2]
&&& y = 'y';[a=code0]
&&& y = 'n';[a=code1]
这是典型的分支语句。走到这段代码之前,我们有一个变量 x,它是个数字,需要判断它是否大于 3。
在[goto=code2] if 语句[/goto]里作判断,如果条件成立( x 大于 3),执行[goto=code0] if 下面的语句[/goto],为变量 y 赋值 'y',此后 y 的值就是‘y‘ 了;如果 x 不大于 3,执行 [goto=code1]else 下面的语句[/goto],为变量 y 赋值 'n'。
无论 x 是几,[goto=code0] if 下面的语句[/goto]和 [goto=code1]else 下面的语句[/goto]只能执行一个。
[/content][/toggle]
[toggle=off]
[title]语句块[/title]
[content]如果要在[goto=code2]上述程序[/goto]的每一分支里多做点事,C 代码如下:
[div=#ffffcc]if( x & 3 )
[size=1][a=code10]{
&&& y = 'y';
&&& z = x - 3;
&&& y = 'n';
&&& z = x + 3;
}[/size][/div]
比上面复杂一点,在判断出 x & 3 是否正确之后,要执行对应的 { } 里面的所有语句。用 { } 括起来的所有语句是一个语句块。例如 x 是 5,执行 [goto=code10]if 后面的语句块[/goto],会为 y 赋值 'y',为 z 赋值 2;若 x 是 1,运行之后的 y 是 'n',z 是 4。
[/content][/toggle]
[toggle=off]
[title]循环[/title]
[content][a=loop][b]循环[/b]是程序运行中,连续多次执行某一段代码的行为,最常用 while 语句或 for 语句。while 较简单,以之为例,C 代码如下:
[div=#ffffcc]x = 1;[a=code20]
while( x &= 4 )[a=code21]
[size=1]{[a=code25]
&&& [size=1]if( x % 3 == 0 )[a=code22][/size]
&&&&&&& [size=1]printf( "%d", x );[a=code23][/size]
&&& [size=1]x = x + 1;[a=code24][/size]
这段代码的作用是取出 1-4 之间所有 3 的倍数。
先为 [goto=code20]x 赋值为 1[/goto],进入 while 循环,[goto=code21]只要 x 不大于 4[/goto],就一遍接一遍地循环执行 [goto=code25]while 后面的语句块[/goto]。
在每次循环中先[goto=code22]判断 x 是否 3 的倍数[/goto][toggle=off]
[title][sup][详][/sup][/title]
[content]在 C 和前述大多数高级语言中,用一个等号 = 表示赋值,如:
[div=#ffffcc]x = 5;[/div]
让 x 的值成了 5;用两个等号 == 判断是否相等,如:
[div=#ffffcc]if( x == 5 )
&&& //x 等于 5 时走这里。
&&& //x 不等于 5 时走这里。[/div]
用百分号 % 求余数,如:
[div=#ffffcc]x = y % 3;[/div]
x 是 y 除以 3 所得的余数,y 若为 3 的倍数(3,6,9,12……),x 就是 0。
所以,[goto=code22]if( x % 3 == 0 )[/goto] 可以判断 x 是否 3 的倍数。
[/content][/toggle],如果是 3 的倍数就[goto=code23]输出 x [/goto](这行代码就是把 x 的值写到显示器上,不必理会细节。)。
判断之后要[goto=code24]把 x 加 1[/goto]。最初 x 是 1,循环一次之后变成 2,再一次变成 3……直到变成 5 时,不再满足[goto=code21] x &= 4[/goto]这个条件,循环结束。如果少了[goto=code24]这条语句[/goto],x 永远是 1,循环永远不结束,就成了[b]死循环[/b][a=deadloop]。
如果还不清楚,请看[toggle=off]
[title]示例代码完整的执行顺序[/title]
[goto=code20]为 x 赋初始值,此时 x 为 1。[/goto]
[goto=code21]进入循环,判断是否满足 while 的条件,满足。[/goto]
[goto=code22]判断是否满足 if 的条件,不满足。[/goto]
[goto=code24]为 x 加 1,x 变为 2。[/goto]
[goto=code21]再次循环,判断是否满足 while 的条件,满足。[/goto]
[goto=code22]判断是否满足 if 的条件,不满足。[/goto]
[goto=code24]为 x 加 1,x 变为 3。[/goto]
[goto=code21]再次循环,判断是否满足 while 的条件,满足。[/goto]
[goto=code22]判断是否满足 if 的条件,满足。[/goto]
[goto=code23]输出 x。[/goto]
[goto=code24]为 x 加 1,x 变为 4。[/goto]
[goto=code21]再次循环,判断是否满足 while 的条件,满足。[/goto]
[goto=code22]判断是否满足 if 的条件,不满足。[/goto]
[goto=code24]为 x 加 1,x 变为 5。[/goto]
[goto=code21]再次循环,判断是否满足 while 的条件,不满足,结束循环。[/goto][/content][/toggle]。
[/content][/toggle]
[toggle=off]
[title]函数调用[/title]
[content][a=func]
[b]函数[/b]是一个具有固定功能和固定接口的语句块。C 代码如下:
第一步,先定义函数:
[div=#ffffcc]int add( int a, int b )[a=code30]
&&& return a +[a=code31]
这是一个最简单的函数,名为 add,它的功能是输入两个整数,输出这两个整数的和。[goto=code30]第一行[/goto]定义了它的[b]接口[/b],其中的 int 表示整数,括号里的 int a, int b 说明要输入两个整数,以 a 和 b 标识。最前面的 int 说明返回值也是一个整数。
函数里面的[goto=code31] return 语句[/goto]用于返回函数执行的结果。
需要调用它时这样写:
[div=#ffffcc]
x = add( 7, 4 )[a=code32];
这样得到的 x 是 11。
在函数定义中用于声明输入类型的参数([goto=code30]上例中的 a, b[/goto] )叫作[b]形参[/b][a=fparam],调用时实际传给它的参数([goto=code32]上例中的 7, 4 [/goto])叫作[b]实参[/b][a=rparam]。
[/content][/toggle]
[toggle=off]
[title]递归[/title]
[content][a=digui]在一个函数里不但可以调用另一个函数,也可以调用这个函数自身,这种情况叫作[b]递归[/b]。C 代码如下:
[div=#ffffcc]void f( int x )[a=code40]
&&& [size=1][a=code41]if( x &= 0 )
&&&&&&&&[/size]
&&& [size=1][a=code42]if( x % 3 == 0 )
&&&&&&& printf( "%d", x );[/size]
&&& f( x - 1 );[a=code43]
这个函数的功能是取出从1到 x 的整数中所有 3 的倍数。如果调用时令 x 为 4,即:
[div=#ffffcc]f( 4 );
它所做的就是取 1-4 中的所有 3 的倍数,等价于[goto=code20]前面见过的循环[/goto]。
先看[toggle=off]
[title]详细解说[/title]
[content]从[goto=code40]这个函数的接口[/goto]可以看出,它需要输入一个整数,返回是 void(空),就是没有返回值。
开始,我们以 f( 4 ); 调用它,看它干了些什么:
形参 x 被赋值为实参 4,面临[goto=code41]第一个判断[/goto],若 x 不大于 0,直接 return 返回,后面的事情都不做了。现在 x 是 4,所以不会 return。
接着是[goto=code42]第二个判断[/goto]和[goto=code20]前面的循环[/goto]里的一样,如果 x 是 3 的倍数就输出。现在 x 是 4,不输出。
[goto=code43]最后一行[/goto],以 x - 1 为实参[b]递归[/b]调用自身。
在这次新的调用中,x 的值变成了 3,是 3 的倍数,因此会在[goto=code42]第二个判断[/goto]里输出。然后又在[goto=code43]最后一行[/goto]以 x - 1 为实参再次递归调用自身,这次 x 变成 2,末尾再次递归调用自身,x 是 1。
每次递归调用 f 时,外面那一层的 f 都没有结束,而是等在那里,到里面的调用都完成时才能结束。调用结构如下图:
[div=#ffffcc|width=300px][toggle=on]
[title]f( 4 )[/title]
[content][toggle=on]
[title]f( 3 )[/title]
[content][toggle=on]
[title]f( 2 )[/title]
[content][toggle=on]
[title]f( 1 )[/title]
[content][toggle=on]
[title]f( 0 )[/title]
[content][/content][/toggle][/content][/toggle][/content][/toggle][/content][/toggle][/content][/toggle][/div]
递归调用一层一层地深入下去,再调用一层,x 的值是 0 了,终于在[goto=code41]第一个判断[/goto]中走到了 return,返回。返回到哪呢?返回到上一层调用函数的位置,也就是上一层 x 为 1 的那一次调用的[goto=code43]最后一行[/goto]。这一行结束之后函数运行结束,又回到 x 为 2 的那一层调用的[goto=code43]最后一行[/goto],这层函数又结束,回到 x 为 3 的那一次调用的最后一行。
最后, x 为 4 的那一次调用也完毕了,整个递归过程结束。[/content][/toggle]。
如果还不清楚,请看[toggle=off]
[title]示例代码完整的执行顺序[/title]
[div=|height=200|overflow-y=auto][goto=code40]以实参 4 调用第一层的 f,在 f 中,x 为 4。[/goto]
[goto=code41]判断第一个 if,不满足条件。[/goto]
[goto=code42]判断第二个 if,不满足条件。[/goto]
[goto=code43]以实参 x - 1 递归调用第二层的 f。[/goto]
[goto=code40]进入第二层的 f,在 f 中,x 为 3。[/goto]
[goto=code41]判断第一个 if,不满足条件。[/goto]
[goto=code42]判断第二个 if,满足条件,输出。[/goto]
[goto=code43]以实参 x - 1 递归调用第三层的 f。[/goto]
[goto=code40]进入第三层的 f,在 f 中,x 为 2。[/goto]
[goto=code41]判断第一个 if,不满足条件。[/goto]
[goto=code42]判断第二个 if,不满足条件。[/goto]
[goto=code43]以实参 x - 1 递归调用第四层的 f。[/goto]
[goto=code40]进入第四层的 f,在 f 中,x 为 1。[/goto]
[goto=code41]判断第一个 if,不满足条件。[/goto]
[goto=code42]判断第二个 if,不满足条件。[/goto]
[goto=code43]以实参 x - 1 递归调用第五层的 f。[/goto]
[goto=code40]进入第五层的 f,在 f 中,x 为 0。[/goto]
[goto=code41]判断第一个 if,满足条件,返回。[/goto]
[goto=code43]回到第四层,执行完毕,返回。[/goto]
[goto=code43]回到第三层,执行完毕,返回。[/goto]
[goto=code43]回到第二层,执行完毕,返回。[/goto]
[goto=code43]回到第一层,执行完毕,调用结束。[/goto][/div]
[/content][/toggle]
[/content][/toggle]
[toggle=off]
[title]函数式编程[/title]
[content][a=hanshushi]如果一个函数能以另外的函数为参数,返回值也可以是一个函数,就具备了[wiki=zh]函数式编程[/wiki]的条件。
C语言虽然有函数指针,写法比较难懂。所以我们改用 [goto=python]Python 语言[/goto]来描述这一特性。在 Python 里我们这样定义一个函数:
[div=#ffffcc]def mod3( x ):[a=code50]
&&& return x % 3 == 0
这个函数用来判断输入的数字是否 3 的倍数。如果调用 mod3( 5 ),会返回一个 False,说明 5 不是 3 的倍数。调用 mod3( 6 ),会返回一个 True,说明 6 是 3 的倍数。
Python 代码与 C 差异较大:1、 def 是定义函数的关键字;2、输入的参数和返回的结果都不需要标明类型;3、数据块不再用 {},而是靠缩进的大小来区分[toggle=off]
[title][sup][例][/sup][/title]
[content][div=#ffffcc]if x & 3:[a=code51]
&&& x = x - 3[a=code52]
&&& y = 'y'[a=code53]
z = 33[a=code54][/div]
在上面这段代码里,[goto=code52]第二行[/goto]和[goto=code53]第三行[/goto]都是只在[goto=code51] if 判断[/goto]成立时才会执行,而[goto=code54]第四行[/goto]却是无论 if 判断成不成立都会执行。因为它的起始位置是与 if 句对齐的,因此它与 if 句是同一级的代码,而非 if 的下级语句块。第二行和第三行的起始位置较 if 句缩进了一块,所以它们是 if 的下级语句块。
如果改写成 C 语言,相当于:
[div=#ffffcc]if( x & 3 )
&&& x = x - 3;
&&& y = 'y';
[/div]虽然 C 代码中往往也有缩进(这是好的编程习惯),但这只是为了好看,不是必须的。而 Python 的缩进是必须的。
[/content][/toggle];4、语句块之前的语句后面要加冒号。5、语句后可不加分号,但必须换行。
函数式编程有以下情况:[hr]
[toggle=off]
[title]参数为函数[/title]
[content]我们有了函数 [goto=code50]mod3[/goto],现在要计算 1-10 这些数字里,有哪个是 3 的倍数,这样写:
[div=#ffffcc]filter( mod3, range( 1, 11 ))[a=code55]
[/div]只要这样一行就行了。连上面的函数定义,一共三行。还记得我们[goto=code20]用 C 语言实现这个功能[/goto]写了多长吗?事实上,如果使用 lambda 匿名函数,一行就够了:
[div=#ffffcc]filter( lambda x: x % 3 == 0, range( 1, 11 ))
[/div]所以,函数式编程最大的好处就是能节省很多代码。
看看它干了什么,外面的 filter 是一个函数,它需要两个参数,第一个参数是另一个函数,第二个参数是一个序列[toggle=off]
[title][sup][注][/sup][/title]
[content]严格地说,是一个可迭代对象。[/content][/toggle]。filter 的作用是以第一个参数(函数)检测第二个参数(序列)里的每一个值,保留通过检测的值,抛弃通不过检测的值。
在[goto=code55]这次调用[/goto]中,先用 range( 1, 11 ) 生成了序列 [1,2,3,4,5,6,7,8,9,10],然后用 [goto=code50]mod3 函数[/goto]逐一检测序列里的数,能让 mod3 返回 True 的就保留,其它扔掉。调用之后返回的值是 [3, 6, 9]。[/content][/toggle]
[toggle=off]
[title]返回值为函数[/title]
[content]如果我们想检测一个数是否 7 的倍数,完全可以仿照 mod3 再写一个 mod7:
[div=#ffffcc]def mod7( x ):[a=code57]
&&& return x % 7 == 0
但如果我们需要很多个这种函数,一个一个地写就很麻烦了。可以用更简单的方式避免麻烦:
[div=#ffffcc]def getMod( n ):
&&& [size=1][a=code56]def mod( x ):
&&&&&&& return x % n == 0[/size]
&&& return mod
getMod 的返回值是一个像 mod3、mod7 这样的函数。在它里面,定义了一个[goto=code56]内部函数[/goto],看上去很像 mod3,它就把这个内部函数返回给调用者。当我们想要 mod3 时,这样写:
[div=#ffffcc]getMod( 3 )
就能得到相当于 mod3 的函数。再要得到 1-10 里 3 的倍数时,这样写就行了:
[div=#ffffcc]filter( getMod( 3 ), range( 1, 11 ))[/div]
当然也可以有 [goto=code57]mod7[/goto],如:
[div=#ffffcc]filter( getMod( 7 ), range( 1, 11 ))[/div]
由此,可以看出函数式编程的灵活性。[/content][/toggle]
有一些函数式编程专用语言,如[wiki=zh]Haskell[/wiki]、[wiki=zh]F#[/wiki]、[wiki=zh]Scala[/wiki]等,应用都不太广泛。
[/content][/toggle]
[toggle=off]
[title]面向对象[/title]
[content][a=oo]面向对象是相对于面向过程来说的。
首先,C或 Python 都支持用点号.表示变量的属性。如,r 是一个矩形,r.length 是矩形的长,r.width 是矩形的宽。如果 r.length 是 4,r.width 是3,r 的周长当然就是 14。写一个计算周长的函数:
[div=#ffffcc]def girth( l, w ):[a=code60]
&&& return 2 * ( l + w )
要计算 r 的周长时,调用 girth( r.length, r.width )即可,这是面向过程的思想。
在编程中,我们觉得这样直接操作 r 的属性是管得太细了,最好让 r 直接告诉我们它的周长是多少。这样我们处理更高层的逻辑时才更容易抓住重点,不至于像诸葛亮一样累死。为此,我们想要这样的调用:
[div=#ffffcc]r.girth()
在 r.girth() 内部,自动去找 r.length 和 r.width,不需要传参数给它。这就是面向对象了。面向对象的三个重要功能是封装、继承、多态。
[toggle=off]
[title]封装[/title]
[content]要实现 r.girth() 这种调用,先忘了前面的 [goto=code60]girth[/goto],新的写法是:
[div=#ffffcc]
class Rect():[a=code61]
&&& def __init__( self, l, w ):[a=code63]
&&&&&&& self.length = l
&&&&&&& self.width = w
&&& def girth( self ):[a=code62]
&&&&&&& return 2 * ( self.length + self.width )
我们用 class 关键字定义了一个[b]类[/b][a=class] Rect,它的含义就是矩形。内有两个成员函数,__init__ 和 girth。这种类里面的成员函数叫作[b]方法[/b][a=method]。现在,如果调用:
[div=#ffffcc]r = Rect( 4, 3 )[a=code64]
我们就得到一个长为 4,宽为 3 的矩形 r[toggle=off]
[title][sup][注][/sup][/title]
[content]创建 r 的时候,实际走到了 [goto=code63]__init__[/goto] 里。在 Python 中,类方法定义的第一个形参(一般叫 self)就是实例 r 本身,从第二个形参才开始接受实参。因此,[goto=code64]创建时传入的实参 4 和 3[/goto],传给了[goto=code63]形参 l 和 w[/goto],然后分别赋值给 r.length 和 r.width(self 就是 r)。[/content][/toggle],可以通过 r.length, r.width 访问它的长和宽,更妙的是,还可以用 r.girth() 直接获得它的周长。
Rect 是 r 的[b]类[/b],r 是 Rect 的[b]实例[/b][a=instance][toggle=off]
[title][sup][例][/sup][/title]
[content]人是类,张三是实例。[/content][/toggle]。用 Rect 描述所有矩形的共性,而 r 表示某一特定的矩形,服从 Rect 描述的共性。不管一个矩形的长、宽是多少,由长、宽计算周长的方法都是固定的。
这种分层级访问数据的思路叫作[b]封装[/b][a=encap]。要控制一个多层组织的运行,仅由一个人安排所有的事,是面向过程;如果由每一部门的负责人安排自己这个部门的事,再共同向总负责人汇报,就是将部门内部的琐事封装起来了。
[/content][/toggle]
[toggle=off]
[title]继承[/title]
[content]一个类可以包括另一个类,它们称为基类和子类。例如人是一个类,但动物是一个更大的类,动物包括人。因此动物是人的基类,人是动物的子类。而男人、女人、亚洲人、科学家又都是人的子类。子类的实例可以使用基类中定义的方法,这种情况叫[b]继承[/b][a=inherit]。例如:
[div=#ffffcc]class Square( Rect ):[a=code65]
&&& def __init__( self, d ):[a=code66]
&&&&&&& self.length = d
&&&&&&& self.width = d
我们定义了一个类 Square——正方形,它是矩形 Rect 的子类。注意[goto=code65]有继承关系的类的写法[/goto]。现在用:
[div=#ffffcc]s = Square( 5 )[a=code67]
就得到一个边长是 5 的正方形 s。创建时也调用了 [goto=code66]__init__[/goto] 方法,它比 Rect 的 [goto=code63]__init__[/goto] 少一个参数。现在,s.length 和 s.width 的值都是 5。
那么 s.girth() 呢?同样没问题,是 20。在类 Square 里并没有 girth 这个方法,于是去它的基类里找,实际起作用的是[goto=code62]类 Rect 里的 girth 方法[/goto]。而在调用 __init__ 时,本身的类里有,就不需要去基类里找了。
在 Java 里,一个类只能有一个基类。而 Python 和 C++ 一样,支持多继承,每个类可以有多个基类。例如正方形既是矩形的子类,也是菱形的子类。无论矩形类还是菱形类里的方法,正方形的都可以调用。
[/content][/toggle]
除了封装和继承,面向对象还有一个功能是多态,这一点对 C++ 是很重要的,对 Python 就无所谓了。在此不细说了。
Java 和 Ruby 是纯面向对象语言,用它们编程,你要写的都是类。C 是纯面向过程的。Python 和 C++ 既可以面向对象的方式编程,也可以面向过程的方式编程。
[/content][/toggle]
[/content][/toggle]
[toggle=off]
[title]四、算法问题[/title]
[content]编程过程中面对的主要问题是算法问题。[a=algo][b]算法[/b]就是以尽可能少的时间及空间投入实现既定目标的方法。我们小时候做过的很多智力题实质就是算法问题,例如:
[div=#ffffcc]有十二个外观相同的小球,其中十一个的重量也相同,另一个与其它的有稍许不同。用一台天平,最少称几次可以确保找出重量与众不同的球?[/div]
[toggle=off]
[title]答案[/title]
[content]三次。
给小球编上号,1-12,[goto=ball0]开始称[/goto]。
[select=1]
[choice=on][title]第一次称[/title][content][a=ball0]天平左边放 1、2、3、4,右边放 5、6、7、8。
[select=1]
[choice][title]若平衡,第二次称[/title][content]现在知道要找的球在 9、10、11、12 里,1-8都是正常的球。
天平左边放 9、10、11,右边放 1、2、3。
[select=1]
[choice][title]若平衡[/title][content]可知要找的球是 12。完毕。[/content][/choice]
[choice][title]若左边较重(右边较重的情况与此相似),第三次称[/title][content]现在知道要找的球在 9、10、11 之中,且比其它球重。
天平左边放 9,右边放 10。
若平衡,要找的球是 11。完毕。
若不平衡,9 和 10 哪个重就是哪个。完毕。
[/content][/choice]
[/content][/choice]
[choice][title]若左边较重(右边较重的情况与此相似),第二次称[/title][content]现在知道要找的球必在 1-8 中,9-12 是正常的。
天平左边放 4、5、6,右边放 7、8、9。
[select=1]
[choice][title]若平衡,第三次称[/title][content]现在知道要找的球在 1、2、3 之中,且比其它球重。
天平左边放 1,右边放 2。
若平衡,要找的球是 3。完毕。
若不平衡,1 和 2 哪个重就是哪个。完毕。
[/content][/choice]
[choice][title]若左边较重,第三次称[/title][content]现在知道要找的球在 4、7、8 之中。若是 4,比其它球重;若是 7、8 之一,比其它球轻。
天平左边放 7,右边放 8。
若平衡,要找的球是 4。完毕。
若不平衡,7 和 8 哪个轻就是哪个。完毕。
[/content][/choice]
[choice][title]若右边较重,第三次称[/title][content]现在知道要找的球在 5、6 之中,且比其它球轻。
天平左边放 5,右边放 6。
哪个轻就是哪个。完毕。
[/content][/choice]
[/content][/choice]
[/content][/choice]
[/content][/toggle]
[div=#ffffcc]A、B两地之间有一条输电线,中间有63根电线杆。现在出了故障,需要判断故障发生在哪一段(两根相邻电线杆之间)上。排查方法是让电工爬上电线杆,分别测试向A和向B的线路通不通。问:在最坏情况下,电工最少爬几次能够确定故障的位置?[/div]
[toggle=off]
[title]答案[/title]
[content]六次。
这是典型的二分查找问题。给电线杆编号 1-63,给A点编号为 0,给B点编号为 64。
先爬上中间的 32 号,确定故障是在 0-32 区间还是 32-64 区间。第二次,仍是爬上[toggle=off]
[title]上回确定的区间的中间一根[/title]
[content]若上回确定故障在 0-32 之间,这回爬 16;若故障在 32-64 之间,这回爬 48。[/content][/toggle],看故障是在前半个区间还是后半个区间。重复这个过程,每爬一次,都把故障范围缩小一半。第六次的时候,确定的区间缩小到两根电线杆之间,就找到故障位置了。[/content][/toggle]
如果你擅长解答这样的问题,开始学习编程吧,在这个领域里有广阔的发挥空间。如果你看过答案仍然不得要领,也学学编程吧,多少会有一些益智作用。
[/content][/toggle]
[toggle=off]
[title]总结[/title]
[content]本教程讲述了以下概念,如果对哪一个还不了解,点回去看。
[goto=program]程序[/goto]、[goto=code]代码[/goto]、[goto=software]软件[/goto]、[goto=proglang]编程语言[/goto]、[goto=remark]注释[/goto]、[goto=if]分支[/goto]、[goto=loop]循环[/goto]、[goto=deadloop]死循环[/goto]、
[goto=func]函数[/goto]、[goto=fparam]形参[/goto]、[goto=rparam]实参[/goto]、[goto=digui]递归[/goto]、[goto=hanshushi]函数式编程[/goto]、[goto=oo]面向对象[/goto]、[goto=class]类[/goto]、
[goto=method]方法[/goto]、[goto=instance]实例[/goto]、[goto=encap]封装[/goto]、[goto=inherit]继承[/goto]、[goto=algo]算法[/goto]
[/content][/toggle]
对本段内容的讨论
点击书签可编辑,清空即删除。

我要回帖

更多关于 amp x 的文章

 

随机推荐