Sie sind auf Seite 1von 147

一天学会Free Pascal

制作者:ax_pokl
前言
• 第一章一向是很重要的,无论你是否学过Pascal语言都
请看一下。
• 本教程不是为了NOIP的人写的,本教程不会过多涉及算
法。那些脑残学很牛逼的牛群们请立即退散。
• 本教程是为了使那些学了C语言(或其它编程语言)能
够瞬间看懂pascal语言程序的人写的。本教程也适合初
学者观看。
• 本教程是本人写的第一个教程,吐槽是可以的但吐得太
多会伤身体。
• 如果有什么问题,欢迎QQ:395838203。
• 发现任何错别字或程序bug,也请联系:395838203。

目录
目录
• 第一章 Pascal语言介绍
• 第二章 编译写好的程序
• 第三章 编写简单的程序
• 第四章 子程序
• 第五章 单元库
• 第六章 编译指令
• 第七章 子界和枚举
• 第八章 数组集合文件记录指针
• 附录

封面
第一章 Pascal语言介绍
• 什么是Pascal?好吃么?
• Pascal语言是什么语言?
• 什么又是机器语言呢?
• 机器语言都是相同的吗?
• X86指令集包括哪些指令?
• 什么是计算机程序?
• 汇编语言又是什么傻逼东西?
• 为什么需要Pascal语言?
• 如何让计算机读懂Pascal语言?
• 编译器是如何运作的?

目录
什么是Pascal?好吃么?
• Pascal的取名是为了纪念十七世纪法国
脑残学家Blaise Pascal(不来色·帕斯
卡)。所以Pascal并不好吃。
一个好看的Pascal语言程序很可能长得像这样:
program hello_world;
begin
writeln('Hello World!');
end.

第一章
Pascal语言是什么语言?
• Pascal语言是计算机程序语言(简称程序语言),使
用这种语言不仅能让我们编写计算机程序,例如:
Windows操作系统、猜数字小游戏、魔兽争霸3,皮卡
丘沙滩排球等等,还可以使我们变得更加脑残。
• 计算机俗称电脑,是一种糟糕物。它通常是一个屏幕,
一个鼠标,一个键盘,和一个黑箱子。有时候人们说
的计算机仅仅指它的黑箱子。
• 这个黑箱子过去曾经是为了帮助脑残学家研究脑残学
才被发明的,它的效果就是帮那些懒惰的脑残学家在
研究脑残学时减少运动量。
• 事实上八成的计算机并不能够读懂Pascal语言。计算
机只能读懂机器语言,对机器语言作出反应。
第一章
什么又是机器语言呢?
• 机器语言是一种只有计算机才读得懂的
语言,也是计算机唯一能够直接读懂的
语言。这种语言只有两个字母:0和1。
人类阅读机器语言时会发生眼残:

第一章
什么又是机器语言呢?
• 世界上只有个别脑残学家看得懂机器语言,所
以我们才需要其它容易看得懂的计算机程序语
言来告诉计算机我们要它做什么。
• 机器语言所有的“单词”的集合,叫做计算机
的指令集。指令集也就是计算机黑箱子能做的
事。
• 比如“01011001010010”是一个机器语言单词,
它的意思是告诉计算机在屏幕上画一个白点。
而计算机所有能做的事,基本上就只是在屏幕
上画白点点了。
第一章
机器语言都是相同的吗?
• 有些计算机不仅能够在屏幕上画白点,
还可以画红点、绿点和蓝点。
• 不是所有计算机懂得的机器语言都是相
同的,它们的能力有高低。
• 通常的家用计算器和笔记本计算机都懂
得X86指令集。这是一个古老的通用的指
令集,即使是今天大多数计算机都认得
它。

第一章
X86指令集包括哪些指令?
1.数据传送指令——就是把数据传来传去,比如传给屏幕。
2.算术运算指令——就是做一些0-255内的简单加减法。
3.逻辑运算指令——就是做一些傻逼的逻辑运算。
4.串指令——顾名思义,就是一串一串执行指令。
5.程序转移指令——就是转移去执行其它的指令。
6.伪指令——计算机不认识的假的指令-_-!
7.其它指令——比如空指令,高级指令,等等。
原来计算机只会做这些傻逼事情。。。。。。
虽然计算机只能够做这些事情,计算机已经显得足够伟大了。

第一章
什么是计算机程序?
• 计算机程序(Computer Program,简称程序)
是语句的集合。语句是单词的集合。
• 为了编写一个机器语言程序,人类发明了汇编
语言。
• 汇编语言的词语是一些英文单词的缩略语和一
些数字。每条缩略语和一些数字的组合与机器
语言指令相对应。这样,人们就不用书写0和1
的机器语言代码了。写完程序后对照书本把英
文单词和数字翻译成0、1的代码就能完成机器
语言程序了。

第一章
汇编语言又是什么傻逼东西?
一个经过反编译的EXE程序
• 事实上,即使有了汇编 至少不再是乱码了
语言(ASM语言),能
够使用英文表达自己的
意思,计算机也只能做
些很傻逼的事。
• 如果要它在屏幕上输出
“你好,妈妈”几个汉
字,你也许需要让它发
送无数个指令给屏幕让
屏幕画很多很多点。于
是就诞生了更加高级的
语言,比如Pascal语言。

第一章
为什么需要Pascal语言?
• 计算机编程语言分三类:机器语言,低级语言,
高级语言。
• 机器语言就是0、1构成的语言。之前我们说的
汇编语言就是低级语言,它唯一的好处就是使
用了英文作为记注符而不是数字。高级语言就
多了,最有名的莫过于C语言了。Pascal语言
也算一种,除此之外还有:FORTAN,C++,
Java,VB,Delphi,Lisp,prolog,等等。
• 还有一些脚本语言虽然不是编程语言,但是也
是计算机语言如:bat,vbs,HTML,asp。

第一章
为什么需要Pascal语言?
• 正因为机器语言、低级语言可读性差,所以我
们需要形如Pascal语言的高级语言来编写程序。
一个Windows操作系统的程序代码重达1G,
它的代码位于%SYSTEMROOT%\System32
下包含几亿条指令。即使一个人一秒能够写一
条指令,它也一辈子都写不完啊!
• 使用Pascal语言我们可以快速准确方便地书写
程序,但是计算机并不能够直接读懂Pascal语
言,所以我们需要一样很重要的东西。

第一章
如何让计算机读懂Pascal语言?
• 编译器(Complier)是一个由某个超级
脑残编写出来的机器语言程序,它能够
让计算机自动将一个Pascal语言程序转
换成机器语言程序。

program hello_world;
begin 编译器
writeln('Hello World!'); Complier
end.

囧!
第一章
编译器是如何运作的?
• 将一个高级语言程序转换成机器语言程序的过程叫做
编译。将一个高级语言程序转换成机器语言程序的原
理叫做编译原理(感觉像是废话)。
• 例如编译器获得“writeln('Hello World!');”这条语句后
就会分析这条语句的语法,然后将得知这条语句其实
就是在屏幕上输出一些白点而已,便把需要做的事转
换成乱七八糟的东西。
• 编译原理十分复杂,因为要理解人类的语言并非易事,
所以只有一些脑残人士才能写的出编译器来。
• 有很多人写过编译器,最有名的莫过于Trubo Pascal
编译器,它的Inline-Complie技术曾震惊全世界。

第一章
在哪里能够得到编译器?
• 当然是网上下载啦~!
• 由于Trubo Pascal编译
器已经过时,这里推荐
Free Pascal编译器:
http://sourceforge.net/p
rojects/freepascal/files/
Win32/2.6.0/
• 如果使用的不是Windows32位操作系统,也可以去
这里下:http://www.freepascal.org/download.var
• 不同的编译器理解Pascal语言略有不同,这造就了略
有不同的Pascal语言语法(语言是随着时代变迁的
嘛)。以后讲到的的Pascal语言语法都是基于Free
Pascal编译器的。
第一章
第二章 编译写好的程序
• 编写你的第一个Pascal程序
• 如何查看程序运行结果?
• 程序出错了怎么办?
• 部分中文计算机用户遇到的问题
• 常用快捷键(请熟记!)
• 大致了解你写的第一个程序
• 编译Pascal程序用到文件的类型
• 调试

目录
编写你的第一个Pascal程序
第一步:打开fp.exe
(请确定你已经正确安装了
free pascal)
然后你会看到形如右边的界面:

第二步:点击File,New
然后在蓝色的背景中
按照左边的图打字。
切记:
不可错一字,不可倒一字,
不可漏一字,不可多一字!
第二章
编写你的第一个Pascal程序
第三步:按F9开始编译
会弹出一个对话框叫你保存。
输入hello_world后按Ok。
如果正常,此时你会看
到如下界面:

第四步:按Ctrl+F9运行程序
你会发现屏幕闪了一下,
这表示你编译并运行成功了。

第二章
如何查看程序运行结果?
• 想知道刚才程序做了什么事,你可以按Alt+F5查看,
或者点击Debug,User Screen来查看。
• 原来傻逼计算机只是在屏幕上输出了一些白点点。

第二章
程序出错了怎么办?
• 当你编译了程序后如果有错误,会出现以下提
示:这时候你按回车,光标会停在错误出现的
后一个字符(没准是下一行)上。你必须修改
错误的部分直到程序能够正确编译为止。
如图,最常见的
错误莫过于分号
漏加。
图中的“;”
except but
“BEGIN” found
意思就是分号漏
加了。 第二章
程序出错了怎么办?
• 在编译的时候出的错叫做编译错误,还有种错误是在
运行的时候出错的,叫做运行时错误。比如你让计算
机去计算3除以0,语法上是没有错误但是不符合逻辑。
• 不同的错误有不同的出错代码,具体请参见附录里的
“Pascal错误码表”。

出错提示中
的(2,1)是出
错的行数和
列数。

第二章
部分中文计算机用户遇到的问题
• 有时候你家的free pascal看上去像这样:
• 请别紧张,这只是脑残计算机在和你看玩笑。这
表现出你家计算机逻辑混乱的另一面。
事实上,出现这种情况
是因为你的计算机使用
了错误的代码页。
你可以建立一个bat脚本
输入以下内容后再运行:
chcp 437 >nul
fp.exe
第二章
常用快捷键(请熟记!)
• Alt + Enter • 全屏
• Alt + X • 退出
• F2 • 保存
• F3 • 打开
• F9 • 编译并连接
• Alt + F9 • 编译
• Ctrl + F9 • 编译连接并运行
• Alt + F5 • 看结果
• F8 • 单步步过运行
• F7 • 单步步入运行
• Ctrl + F8 • 加断点
• Ctrl + F7 • 加跟踪变量
第二章
大致了解你写的第一个程序
program hello_world; {程序总是以program和一串英文字母开始}
{单词之间用空格隔开}
begin {程序的语句部分开始}
writeln('Hello World!'); {输出一个字符串}
end. {程序总是以end和一个英文半角句号结束}
{大括号里写的都是注释}
{注释会被编译器忽略}
(*除此之外,你还可以用
一个半圆左括号加一个星号和
一个星号加一个半圆右括号表示一段注释*)
1+1=3 //程序结束以后加什么内容编译器
//都懒得鸟你,一行内的两根斜杠后面的
//内容也会被认为是注释。
{你甚至还可以用//嵌套的方法}//表示这是注释!
{原来一个pascal语言程序就是这么写的。}
栗子:hello_world.pas
第二章
编译Pascal程序用到文件的类型
.pas 程序源代码
.bak 程序源代码的备份
.o 目标文件(经过编译的源代码)
.exe 编好的程序(经过连接的目标文件)
.pp 单元库文件
.ppu 经过编译的单元库文件
.inc 源代码的一部分(头文件)
.pas 编译 .o 连接
.ppu .pp .exe

第二章
调试
• 你可以在学习编写简单的程序以后再来看这一节。
• 调试是一种检查程序运行时错误的重要手段。
• 当你学会了一些编程方法并能够熟练书写程序以后,
编译错误已经不再是你畏惧的东西了,但运行时错误
将永远陪伴你。
• 世界上最讨厌的事不是程序中有错,而是不知程序的
错出在哪里。
• 一个程序编写完以后进行运行。如果运行的结果和期
望的不同,那就需要调试修改。

第二章
调试
• 按F8进行一句一句执行。
• 如果错误出线在某个子程序内,可以按F7进入子程序
一句一句执行,F7也会跟进其它文件内的子程序。
• 按CTRL+F7输入变量名称,随时查看变量的值。
• 所有的调试功能都在菜单中的debug中。
• 除了F8和F7以外,你还可以使用F4直接执行到某一条
语句后停止。
• 除此之外,使用CTRL+F8添加程序断点以后再用
CTRL+F9也是一种可取的调试方法。

第二章
第三章 编写简单的程序
• 语句和程序段 • 优先级
• 最简单的程序 • 让计算机进行简单的数学运算
• 更高级的程序 • 赋值
• 常量和变量 • 交换两个变量的值
• 条件
• 关键字和标识符
• 让计算机求解一元二次方程
• 数据类型
• 循环
• 定义常量和变量 • 嵌套
• 操作符 • 猜数字游戏
• 运算符 • 空语句

目录
语句和程序段
• 一条语句就是一个句子(俗称一句话,-_-!我不知道
该怎么解释)。
• 除了begin和end.外,Pascal的每条语句都是以;结尾的。
• 一个程序段就是一段程序,程序段又称为复合语句。
• 程序段是由begin,一些语句和end;构成的。
• 语句的种类可多了,在以后的学习中你将一一接触不
同的语句。
• 之前我们能遇到的writeln('Hello World!')是条语句,它
其实是调用了SYSTEM单元库中的一个叫做writeln();
的过程(过程是子程序的一种)。

第三章
最简单的程序
• 一个最简单的程序包含一个程序说明和一个主程序段:
program program1;{主程序说明}
{定义主程序的各种变量和常量}
begin {主程序段开始}
writeln('我是一个语句');{主程序段内容}
end. {主程序段结束}
• 主程序段也是程序段,只不过它结尾的最后一个end是
以英文半角句号而非分号结束的。也就是说,pascal
语言程序的最后一条语句一定是end.。

第三章
更高级的程序
• 如果你认为Pascal语言只不过是只能在屏幕上
输出“Hello World!”的傻逼语言,那么你就错
了,因为其实它还能输出更多东西,比如:
“caonima!”。。。。。。因为,认真你就输
了。 program input_output;
var s:string;
begin
readln(s);
writeln(s);
end.
栗子:input_output.pas
第三章
常量和变量
• 虽说魔兽争霸3也只不过是屏幕上的一些白点
点,但是要完成魔兽争霸3,我们还需要更多
的手段。
• 上面一段程序和hello_world.pas不同的是,它
使用了var s:string定义了一个字符串变量。
• 一个变量(或常量)可以用来储存信息,例如
一串文字(字符串类型),一个数字(整数类
型、实数类型)。貌似只有这些功能。

第三章
常量和变量
• 使用const关键字来定义常量。
• 使用var关键字来定义变量。
• var s:string;,中的s就是一个变量,string是它
的数据类型(字符串类型)。
• 通过readln(s);语句,我们可以在屏幕里输入一
串文字并保存到变量s中,下次就可以直接用
writeln(s);输出字符串s了。
• 别忘了,定义一个变量以后也需要加分号。

第三章
关键字和标识符
• 不是随便一串英文字母都可以用来定义变量的。一个
变量(或常量)的名称叫做变量(或常量)的标识符。
• 标识符不能是关键字(又称保留字)。
• 标识符不能重复定义。你可以假定关键字是已经被定
义的标识符。
• 标识符不能以数字开头,并且必须由英文字母、数字
和下划线组成。标识符是不区分大小写的。
• 关键字就是Pascal语言预定好的有特殊含义的单词,
如program,const,var,begin,end等等。
• 如果你打入了一个单词是白色的,那他就是关键字了,
所以别把关键字用作标识符。(常用的关键字见附录
中的“常用关键字列表”)

第三章
数据类型
• 每个变量或常量都有它自己的数据类型。
• 数据类型决定了数据是如何存储在内存中的。
• 除了字符串类型(string)以外,还有很多数据类型:
• 整数类型(integer) 字符类型(char)
• 实数类型(real) 布尔类型(boolean)
• 数组类型(array) 集合类型(set)
• 枚举类型(()) 子界类型(..)
• 文件类型(file) 指针类型(^)
• 记录类型(record) 对象类型(object)
• 这些类型都有自己的定义和使用方法,将在之后的章
节一一介绍。
第三章
常用数据类型(整数类型)
• 整数类型 能表示的数字范围 占用内存
• Shortint -128~127 1
• Integer -32768~32767 2
• Longint -2^31~2147483647 4
• Int64 -2^63~2^63-1 8
• Byte 0~255 1
• Word 0~65536 2
• Cardinal 0~4294967926 4
• 能表示的数字范围越大,占用的内存也就越多。

第三章
常用数据类型(实数类型)
• 实数类型 能表示的数字范围 占用内存
• Real Singel或Double 4或8
• Single 1.5E-45 .. 3.4E38 4
• Double 5.0E-324 .. 1.7E308 8
• Exended 1.9E-4951 .. 1.1E4932 10
• Comp -2E64+1 .. 2E63-1 8
• 内存,又称主存,是你计算机中的一个配件,需要花
钱购买。内存越大则价格越高。如果内存不够用了,
你的程序就会崩溃。
• 内存使用的单位叫做字节,一个字节相当于八个开关。

第三章
常用数据类型(布尔、字符类型)
• 布尔类型 能表示的数字范围 占用内存
• Boolean false或true 1
• 字符类型 能表示的数字范围 占用内存
• Char #001~#128 1
• 具体1到128号数字表示什么字符,请参见附录中的
“ASCII码表”。
• 其它表示方法:
• Integer &01001000100101001010
• Integer $7F23A8D2
• Char 'a'

第三章
常用数据类型(字符串类型)
• 字符串类型 能表示的数字范围 占用内存
• String #0x???????? 8
• 字符串类型其实是一个引用类型,它的值指向内存中
的一个地址。字符串类型是一种特殊的类型。
• 输出的字符串必须用单引号括起来,否则计算机会把
它当成一个变量,例如writeln(abc);和writeln('abc');的
含义是完全不同的。

第三章
定义常量和变量
program pi_const; • 使用=定义常量。
const • 使用:定义变量
PI=3.1415926535897932384
62643383279502884197169 • 常量的值是不可修改的。
39999999999; • 虽说可以用变量来代替常量,
{π其实是个有理数} 但是常量的使用可以使程序
var d:integer; 更简洁并。程序中过多的数
begin 字(硬编码)的出现不易于
write(‘请输入直径’); 程序的修改和维护。
readln(d);
• 常量先于变量而定义,在定
writeln('周长',PI*d);
义某些变量时甚至可以直接
end. 使用到常量(如数组)。
栗子:pi_const.pas
第三章
操作符
• 对变量进行运算、赋值的符号叫做操作符
(Operator)。运算符是操作符的一种。
• 数学运算符 关系运算符 逻辑运算符
• 加法:+ 等于:= 且:and
• 减法:- 大于:> 或:or
• 乘法:* 小于:< 否:not
• 除法:/ 大于等于:>= 异或:xor
• 整除:div 小于等于:<=
• 取余数:mod 不等于:<>

第三章
运算符
运算符 操作数类型 结果类型
+,-,* 整型或实型 整型或实型
算术运算 / 整型或实型 实型
div,mod 整型 整型
=,<> 除文件各种数据类型
<,> 标准,枚举,子界
关系运算 布尔
<=,>= 标准,枚举,子界,集合
in 顺序类型、集合
逻辑运算 not,and,or,xor 布尔 布尔
集合运算 +,-,* 集合 集合
赋值运算 := 除文件以外 除文件以外

第三章
优先级
• 学过小学数学的小朋友都知道,数学运算都是
从左往右进行的。乘除法的优先级高于加减法。
• ()
• not, ~,@
• *, /, div, mod, and, &, as, shl, shr
• |, !, +, -, or, xor
• =, <>, <, <=, >, >=, in ,is
• else then

第三章
让计算机进行简单的数学运算
program a_plus_b_1; program a_plus_b_2;
var a:integer; var a,b:integer;
b:integer; {定义两个变量时,
begin 可以把它们写在一起。}
readln(a); begin
readln(b); readln(a);readln(b);
writeln(a+b); {语句也是如此}
end. writeln(a+b); end.
栗子:a_plus_b_1.pas 栗子:a_plus_b_2.pas
第三章
字符串连接操作符*
program a_b_s1_s2; 输入:
1
var a,b:integer; 2
s1,s2:string; 输出:
3
begin 输入:
1
readln(a); readln(b); writeln(a+b);
2
readln(s1); readln(s2); writeln(s1+s2); 输出:
end. 12

{不同的数据类型之间,操作符的效果也是不同的。}
栗子:a_b_s1_s2.pas
第三章
赋值
• 变量和常量的区别在 program set_i;
于,变量的值是可以 var i:integer;
改变的。
begin
• 赋值符号::=
i:=1024;
• 赋值符号也是一种操
writeln(i);
作符。
end.

栗子:set_i.pas

第三章
交换两个变量的值(低级)
• 利用第三变量c来交 program a_b_c_easy;
换两个变量的值。 var a,b,c: integer;
begin
• 这个程序的优点是简 readln(a,b);
单,缺点是需要用到 c:=a;
第三个变量。-_-! a:=b;
b:=c;
writeln(a,b);
end.

栗子:a_b_c_easy.pas
第三章
交换两个变量的值(中级)
• 利用数学运算操作符来 program a_b_c_normal;
交换两个变量的值。 var a,b: integer;
• 第一行a变成了一开始的 begin
a+b。 readln(a,b);
• 第二行b变成了a。 a:=a+b;{a变成了和}
• 第三行,由于a是a+b, b:=a-b;{a+b-b=a}
b是a,相当于a+b-a=b。
a:=a-b;{a+b-a=b}
• 这个程序的优点不需要
用到第三变量,缺点是 writeln(a,b);
有可能会溢出,例如输 end.
入a=20000,b=20000。
栗子:a_b_c_normal.pas
第三章
交换两个变量的值(高级)
• 利用位运算操作符来 program a_b_c_hard;
交换两个变量的值。 var a,b: integer;
• 这个程序的优点就是 begin
一个字:牛逼。 readln(a,b);
• (xor是对整型的每 a:=a xor b;
位进行异或运算,不 b:=a xor b;
懂的问老师吧,反正 a:=a xor b;
xor平时不需要。使 writeln(a,b);
用位运算还可以加快 end.
程序执行速度。)
栗子:a_b_c_hard.pas
第三章
条件(if)
• 尽管我们已经能让计算机进行一些简单的数学运算并
将结果输出出来,但是要完成魔兽争霸3,我们还需要
一种很重要的语句:条件语句。
if a=b then c:=512;
• a=b可以是任何一个布尔变量,还记得运算符号一节中
有说关系运算符“=”的输出结果是布尔类型么?
• 如果使用多个布尔变量,切记用括号括起来:
if (a=b) and (c=d) then e:=128;
• 下面一条语句将永远不会被执行:
if false then writeln('I am stipud.');

第三章
条件(程序段)
• then之后跟的语句可以是一条语句,也可以是
一个程序段:
if c=d then
begin
a:=b;b:=b+b;
end;
• 切记,如果要写两条语句,必须将这两条语句
写在程序段的begin和end;之间,否则第二条
语句将不在条件语句的判定内(一定会被执
行)。

第三章
条件(if-else)
• if-else语句:
if a=b then c:=512 else d:=215;
• 相当于:
if a=b then c:=512;
if not(a=b) then d:=215;
• 切记,无论else前的语句是一条语句还是一个
程序段,else前的那一个分号必须删掉!
if a=b then begin c:=d;e:=f;end else g:=h;

第三章
让计算机求解一元二次方程
program yi_yuan_er_ci; if d<0 then
var a,b,c,d:real; writeln('方程无解!')
begin else
write('请输入a:');readln(a); begin
write('第一个解是:');
write('请输入b:');readln(b);
writeln((-b+sqrt(d))/2/a);
write('请输入c:');readln(c);
write('第二个解是:');
d:=b*b-4*a*c; writeln((-b-sqrt(d))/2/a);
end;
end.
栗子:yi_yuan_er_ci.pas
第三章
循环
• 例如我们要一下子重复输出1000句话,一种方
法是把writeln('我是剑圣');复制1000遍。但是
这种办法十分坑爹而且写出来的程序十分庞大。
另一种方法就是使用循环语句。
• 加入你在魔兽争霸中需要显示1000个剑圣,这
1000个剑圣分别叫做“剑圣1”,“剑圣2”,
“剑圣3”…“剑圣1000”,这时候你就不得不使
用循环语句了。
• 循环语句有三种:while语句,repeat-until语句
和for语句。

第三章
循环(while)
• 理论上说,使用while语句可以完成其它循环语句所能
做到的所有的事。
• while语句用起来是这样的:
a:=1;
while a<=1000 do
begin
writeln('我是第',a,'句话');
a:=a+1;
end;
• 和if语句一样,当while后的布尔值是true时就执行后面
的语句或程序段,只不过执行完一遍以后还会重新判断
是否再次执行。

第三章
循环(repeat-until)
a:=1; a:=1;
repeat while a<=1000 do
writeln('我是第',a,'句话'); begin
a:=a+1; writeln('我是第',a,'句话');
until a=1000; a:=a+1;
• 这段程序和右边的程序 end;
效果是一样的。无论如 • 和repeat-until不同的是,
何,repeat-until之间的 repeat-until之间可以是
语句一定会执行一遍, 多条语句,而while后必
因为判断是在until执行 须是一条语句或者一个
的。当until后的布尔值 程序段。
为true时就跳出循环。 • until前可不加分号。

第三章
循环(for)
for a:=1 to 1000 do a:=1;
writeln('我是第',a,'句话'); while a<=1000 do
• 这段程序的效果和右边 begin
的是一样的。 writeln('我是第',a,'句话');
• for语句总是很简洁,但 a:=a+1;
是并非所有循环都能用 end;
for语句表示出来。 • 总能把for语句用while语句
• for语句的循环体变量 表达出来。
(这里是a)的值是不可 • 学会把for用while写出是很
改变的。 重要的,因为有时候你没
法把循环用for表达出来。

第三章
循环(for-downto)
• 可惜的是,for语句不支 program goto_10086;
持C语言中的步长功能, label 10086;{定义一个标记}
每次循环循环体变量的 begin
值只会加一。 b:=1000;
• 尽管如此,for语句提供 10086:{在这里标记10086}
了另一种方法来表达减 writeln('我是第',b,'句话');
一: b:=b-1;
for b:=1000 downto 1 do if b>=1 then goto 10086;
writeln('我是第',b,'句话'); {跳转到标记10086}
end.
• 使用goto语句来达到目的

第三章
循环(goto)
• 使用goto语句虽然有时候能使书写程序变得简
便,但是通常情况下它会破坏程序结构。它会
让程序不止一个出口,所以应该避免使用。
• 理论上所有的循环都可以用while语句来完成。
• 同样道理,break和continue这些会破坏循环结
构的语句也应该避免使用,它们是万恶之源,
因此在此不再介绍此类语句的使用方法。(就
不告诉你,就不告诉你,就不~告诉你!)

第三章
嵌套
• 举个栗子你就明白了:
if a>b then
if c>d then
begin
while e=f do
g:=g+1;
if (1+1)=3 then writeln('好的');
end;
• else后面也可加嵌套,即else if…,分号加不加自己多
试试就知道了。

第三章
猜数字游戏
• 好了,现在你已经有能 program cai_shu_zi;
力让计算机在屏幕上持
续得画一大堆点了,虽 var a,b,i,n:integer;
说离写出魔兽争霸3还有 begin
很长的一段路要走,但 a:=1;{最大值}
是凭借这点知识写一些
小游戏已经不成问题了。 b:=100;{最小值}
• 如果你能理解这个程序, writeln('请输入一个1-100
并且正确预料这个程序 的整数:');
运行后将会发生什么,
那么恭喜你,你已经学
会编写一个简单的 栗子:cai_shu_zi.pas(上半部分)
Pascal语言程序了!

第三章
猜数字游戏
for i:=5 downto 1 do else
begin begin
write('你还有',i,'次机会:'); write('数字太大了傻逼!');
readln(n);{输入的数} b:=n;
if ((b-n)-(n-a)>0) then end;{else}
begin end;{for}
write('数字太小了傻逼!'); writeln('你已经没有机会了。');
a:=n; writeln('你真是个大傻逼!');
end{if} readln();
end.
栗子:cai_shu_zi.pas(下半部分)
第三章
空语句
• 一个典型的空语句:
;
• 空语句用在条件语句上:
if a=b then ;
• 空语句用在循环语句上:
while true do ;{死循环}
• 加了空语句不会怀孕:
;;writeln('加了空语句不会怀孕');;;;

第三章
空语句
program hello_world_void;
begin;
writeln('Hello World!');
end.
{除了程序名外仔细观察这段程序
和之前的hello_world程序有什么不同
这段程序能否通过编译?为什么?}
{答案:能。
begin之后的那个分号相当于空语句。}

栗子:hello_world_void.pas

第三章
条件(case)*
• 虽然本作者一向不推荐使用case语句,但是作为一个
优秀的程序员必须对所有可能出现的语句做一个了解,
因为你不用不代表别人不会用,到时你看到case语句
说这不是pascal语言因为我没教过我就傻眼了:
case i of{这里不加分号}
1:writeln('ok');
2:a:=b;
3..5:if (1+1)=3 then writeln('yes!');{3..5是子界,有关子
界的内容请参看后面几章}
else:while true do ;{这里的分号可以不加,只不过这里
用了空语句}
end;

第三章
循环(break)*
• 我不推荐大家使用case语句是出于两个原因,第一是
因为case语句局限性很大,第二是因为begin和end;不
是对称的,case语句中没有begin。
• 在这里顺便也把break的用法说了吧,还是举栗子:
a:=1;
while true do
begin
a:=a+1;
if a>1000 then break;
end;
• 就是这样,看不懂也别来问我,只能说你学艺不佳。
第三章
第四章 子程序
• 函数与过程 • writeln();和readln();
• 参数 • 场宽(:操作符)
• 返回值 • 使用其它子程序
• 局部变量和全局变量 • 程序也是子程序
• 实际参数和形式参数 • 操作符也是子程序
• 重载
• 递归
• 超前引用(forward)

目录
函数与过程
• 细心的小朋友已经发现,在求解一元二次方程中,我们
使用了sqrt();来求解一个实数的平方。sqrt();就是一个子
程序。
• Pascal的子程序分为两种,一种叫做函数(Function),
如sqrt();,另一种叫做过程(Procedure),如writeln();。
函数于过程的区别在于,函数是有返回值的。例如:
a:=sqrt(b);
• 但是这样是错误的:
c:=writeln(d);{这是错误的}
• 因为writeln();只是一个过程,它并没有返回值。

第四章
函数与过程
• 子程序可以理解为“一个独立的程序段”。它
的结构就和一个程序一样。
• 子程序名是一个标识符,例如一个过程:
procedure procedure1();{过程说明}
{定义各种变量和常量}
begin {过程程序段开始}
writeln('我是一个语句');{过程程序段内容}
end; {过程程序段结束}

第四章
参数
• 参数其实就是变量。
• 在使用writeln();时,你会键入writeln('大傻逼');,
这个“'大傻逼'”就是一个参数,如果没有这个
参数,writeln();只会在屏幕上输出一个空行。
• 参数的出现使得子程序的效果产生各种变化。
一个参数可以是一个变量。使用参数是主程序
将变量的值传给子程序的一种手段。

第四章
返回值
• 只有函数有返回值。
• 你可以把函数本身看成一个变量,例如:
function inc(i:integer):integer;
begin
inc:=i+1;
end;
• 在定义函数inc的同时,你就同时已经定义了一个叫inc
的整数类型变量。当你把参数传递给函数时,就可以
使用它返回的值了,例如:
b:=inc(a);

第四章
局部变量和全局变量
program bian_liang; • 局部变量c是在子程序内
var a,b:integer; 定义的,所以在主程序
procedure procedure1(); 段不能使用变量c,否则
var a,c:integer; 会报错。
begin{过程开始} • 全局变量b在子程序内也
能使用。
a:=a+1;b:=b+1;c:=c+1;
• 变量a在子程序外和子程
end;{过程结束}
序内都有定义。被定义
begin{主程序开始} 的是两个不同的变量。
procedure1(); • 过程段内改变的是局部
a:=a+1;b:=b+1; 变量a的值,主程序段改
end.{主程序结束} 变的是全局变量a的值。
第四章
实际参数和形式参数
program can_shu; • a,b,c是实际参数,它们的值
var a,c:integer;b:real; 无论在子程序内还是子程序
function abc(i:integer):real; 外都会被改变。q是变量参数,
var q:integer; 只在子程序内起效果,用完
就结束了,其中i是形式参数,
begin 调用结束时值会返回给c。
i:=i+1;a:=a+5; • i和c是两个不同的变量,你不
abc:=i;q:=q+2; 能在子程序外使用i。
end; • 无论是何种参数,本作者都
begin 不建议通过参数来传递返回
b:=abc(c); 值。最好的方法还是使用
end. abc:=i;的方式传递。

第四章
重载
• writeln('abc');和writeln();其实是两个不同的子程序。
• 参数不同的同名子程序不是同一个子程序,同名参数
不同的子程序叫做子程序的重载,一个子程序可以有
无数个重载:
procedure procedure1(a:integer);
begin a:=a+1;end;
procedure procedure1(a,b:integer);
begin a:=a+2;b:=a+3;writeln('我是重载');end;
procedure procedure1(s:string);
begin writeln(s);writeln('即使类型不同也可以重载');end;

第四章
递归
• 递归其实就是子程序调用它自己
• 调用自己难道不会出现死循环么?看这个:
function jie_cheng(canshu:integer):longint;
begin
if canshu>0 then
jie_cheng:=jie_cheng(canshu-1)*canshu
else
jie_cheng:=1;
end;
• 递归是一种常用算法,它通常可以大大优化程序,提
高程序运行效率,节省内存和钞票。

第四章
超前引用(forward)
• 有时候子程序需要相互调用,但是pascal子程序必须
先定义才能调用,怎么办?看这里:
procedure play();forward;
procedure menu();
var a:integer;
begin readln(a);if a=1 then play();end;
procedure play();
var a:integer;
begin readln(a);if a=5 then menu();end;

第四章
writeln();和readln();
• writeln();和readln();都是过程。
• writeln();和readln();都可以使用多个参数。
• write();和writeln();的用法我就不说了,自己试。
• 虽然read();和readln();都是以回车来结束读取的,但是
read();读取是按空格为分隔符来的。
• 反正我只支持使用readln();来读数据,并且每次最好只
读一个。
• 其实更好的方式是使用其它单元库的其它子程序来读
数据,例如keypress(),getMouseEvent()等等。

第四章
场宽(:操作符)
• 输出的数据不够整齐?场宽能够帮助你!
for i:=1 to 100 do write(i:5);
• 场宽也能够限制输出数据的长度:
for i:=10000 to 10100 do write(i:3);
• 还有一种双场宽用于输出实数:
writeln(1111.222222:3:4);
• 前一个冒号后是整数部分长度,后一个冒号后是小数
部分长度。
• 输出实数时小数部分是四舍五入的。

第四章
使用其它子程序
• SYSTEM单元库中除了writeln();和readln();以
外,系统中其实还有许多其它可用的子程序,
例如ord();,chr();,sqr();,sqrt();,abs();,
trunc();,round();等等,详细请见附录中的
“常用子程序列表”。
• 除了SYSTEM单元库外,你还可以使用其它单
元库,例如CRT单元库,这个单元库里有
delay();,sound();等子程序。有关单元库的内
容将在下一章介绍。

第四章
程序也是子程序
program inc(i:integer):integer;
begin
inc:=i+1;
end;
• 说对了,我们的程序其实也是个子程序。当我们用外
面的命令或别的程序调用它时,也能获得和子程序一
样的效果。
• 当一个子程序没有参数时,我们可以把它的括号省略,
例如:
function function_abc:integer;
• 平时我们定义的program program1其实就是个即没有
参数又没有返回值的子程序。

第四章
操作符也是子程序
• 你以为:=是和+是系统预定的?那你就错了。操作符的
本质也是子程序。
operator + (a,b:integer):integer;
begin
asm {…} end;
end;
• 这是一个加法操作符的定义,它是用pascal内嵌的汇
编语言实现的。我们知道汇编语言是脑残使用的语言,
所以我在这里就不多讨论了。
• 操作符也是可以重载的,具体方法就是看上面的格式
使用operator关键字,懒得多说了。

第四章
第五章 单元库
• 使用CRT和GRAPH单元库
• SYSTEM单元库
• 书写一个单元库
• .pp文件和.ppu文件、.o文件的关系

目录
使用CRT和GRAPH单元库
• 使用uses语句可以使用单元库预编好的子程序。
• 每个程序只能有一个uses语句。
• uses语句必须紧紧跟在program语句之后。
program program1;
uses CRT,GRAPH;
begin writeln('随便写点内容');clrscr();end.
• 和SYSTEM单元库一样,CRT、GRAPH单元库的子程
序也写在附录的 “常用子程序列表”中。
• 使用GRAPH单元库时必须先初始化绘图窗口,自己找
参考书吧,GRAPH确实单元库是一个强大的单元库。

第五章
SYSTEM单元库
• 你在书写程序之前,系统已经默认隐藏包含了uses
SYSTEM;这条语句,这就是为什么你能使用writeln();
子程序的原因。
• 在SYSTEM单元中不仅包含了很多子程序,还定义了
很多类型,例如integer,char等等。
• 在源码中的systemh.inc中我们还可以发现,SYSTEM
单元库包含了mathh.inc和currh.inc等代码,也就是说
我们无需使用MATH单元库就可以使用MATH单元库内
预定的子程序等内容。
• 作者建议大家看一下源码system.fpd内的内容,
system.fpd的内容已经写在附录中。

第五章
书写一个单元库
• 这不难,看个栗子就知道:
unit unit1{单元库声明}
interface{关键字,不可省略}
const const1=10086;
var i:integer;{定义各种常量和变量}
procedure procedure1();{这里不用写出程序段,只需写
出子程序声明,可以写很多个}
implementation{另一个关键字,不可省略}
procedure procedure1();{再写一次声明}
begin writeln('ok');end;{这里写出程序段}
end.{和一个程序一样结束一个单元库}

第五章
.pp文件和.ppu文件、.o文件的关系
• 我们通常把单元库的代码保存为.pp文件而
非.pas文件。与.pas文件不同的是,按Alt+F9
将.pas文件被编译后只生成.o文件,而.pp文件
被编译后会生成.ppu和.o文件。
• 如果.pas文件有使用单元库,则会寻找该单元
库的.pp文件,如果没有找到.pp则会寻找.ppu
和.o。
• 把所有的.o文件用link.exe(或者make.exe)
连接起来就成了可运行的.exe文件了。当然
link.exe也可以将.o文件连接成.dll文件。

第五章
第六章 编译指令
• .inc文件和{$I}
• 编译指令{$define}和{$ifdef}
• 了解Windows API
• 调用外部子程序
• 内嵌汇编语言

目录
.inc文件和{$I}
• 如果你心情好去官网上下Free Pascal的源码,在source
文件夹里除了.pas,.pp你还会发现很多.inc文件。
• .inc文件是没法通过编译的,因为它只是源代码的一部分。
• 如果你有一个文件叫abc.inc,在你的程序中有一句{$I
abc.inc},这相当于abc.inc的所有内容全部都照抄到这条
语句的这个位置了。
• 当然,如果在abc.inc中已经加入{$I cba.inc},那么在照
抄abc.inc之前会先将cba.inc照抄进去。如果找不到所有
所需的文件就无法通过编译,编译时会停留在出错的{$I
abc.inc}或{$I cba.inc}上。

第六章
.inc文件和{$I}
• 同一个.pas可以{$I}同一个文件多次,不同
的.pas文件或.pp文件也可以{$I}同一个文件。
甚至可以互相{$I}。
• {$I}是种编译指令,编译指令都是以“{$”开头
的,在编译一个程序之前make.exe会先找到所
有编译指令并进行处理,然后再编译。在
make.exe之后也可加各种参数来达到同样的效
果例如-I abc.inc。

第六章
编译指令{$define}和{$ifdef}
• 刚才说到两个.pas互相{$I}对方,难道不会出现死循环
么?有什么东西能先于{$I}阻止它们吗?有,那就是编
译指令本身。
• 编译指令又叫编译开关,因为编译器最终要将pascal
语言转成机器语言,而每种机器懂得的机器语言又略
有不同,所以我们需要提供更多的信息告诉编译器如
何把自己的代码编译成机器语言,例如你用的机器使
用何种指令集。
• 我用{$define haha}定义了一个叫haha的东西,haha
只是有被定义和没有定义两种状态。定义了当然是有
用处的。

第六章
编译指令{$define}和{$ifdef}
• 接下来就有{$ifdef haha}uses CRT;{$endif}就是如果定
义过了haha那么这个地方就有“uses CRT;”这条语句,
否则这个地方就啥都没写,编译器会忽略这段话。
• 你觉得这很麻烦?写了又不用为什么不直接不写?这
就好像为什么要把程序分块写成子程序一样,为了易
于修改。想想看如果把源码拷贝到另一台电脑只要改
开头的{$define haha}不需要去删除那修改程序不是很
方便么?
• 除此之外你还可以用{$undef}来取消来取消一个定义,
用{$else}控制另一段代码是否使用,甚至你还可以嵌
套这些编译指令。

第六章
其它编译指令*
• {$APPTYPE GUI} 可在写windows程序的时候
去掉DOS黑框框。
• 在用DOS单元前{$M $4000,0,0}不然Dos单元
的部分函数会出问题。
• 更多编译指令请见附录“Pascal编译指令”。

第六章
了解Windows API
• 前面说到了SYSTEM系统单元库,实际上系统单元库
也是人写出来的(废话)。那么诸如writeln();这种子
程序在系统单元库是如何实现的呢?其实它是调用了
Windows API。
• Windows API是比尔盖茨的同事们为了自己和大家方
便写的一系列动态链接库(DLL),它的地址位于
%SYSTEMROOT%\System32,包括kern32.dll,
user32.dll等。这些DLL通常使用C++语言写成的,经
过编译后变成了机器语言。Pascal语言程序可以使用
external和name关键字使用这些在操作系统中预先存
在的DLL,实现各种功能(比如在屏幕上画白点点
等)。

第六章
调用外部子程序
• 看看附录里的free pascal源码func.inc是
如何定义所有Windows API子程序的你
就能学会如何使用name和external关键
字调用外部子程序了。

第六章
内嵌汇编语言
• 别嵌了,先去学汇编语言,然后再去学
混合语言编程技术。这一块已经不属于
Pascal语言的犯愁了。
• 反正你看到asm和后面一大堆绿色代码
就忽略掉吧。

第六章
第七章 子界和枚举
• 定义数据类型
• 子界
• 枚举
(这一章很短,你知道为什么的)

目录
定义数据类型
• 使用type关键字,你可以定义新的数据类型,例如:
type mytype=integer;
• 然后你就定义了一个叫mytype的数据类型,这个数据
类型和integer效果一样,只是换了个名称。(-_-!不是
浪费时间么)
• 系统中自带定义了很多其它类型如type qword=int64;,
它的目的是为了让其它语言的程序员也可以使用这种
类型,因为在其它语言中也许int64就叫做qword。
• 接着你就可以使用var a:mytype;或者var b:qword;了。

第七章
子界
• 你以为integer,boolean等数据类型都是系统预定的?
那你就对了!-_-!
• 但是,何谓预定,这是一个问题。对于integer这样的
数据类型来说,它是可以用其它方法来描述它的。
type integer=-32768..32767;
• -32768..32767是一个子界类型,它是pascal里的一个
基本类型。
• 所有整数类型都是用子界类型来定义的,这不难。
• 在系统源码systemh.inc中有这么一样东西:
const maxLongint=$7FFFFFFF;
• 接着就可以这么定义longint类型:
type longint=(-maxLongint-1)..(maxLongint);

第七章
枚举
• 那么boolean又是如何定义的呢?
• 把所有可能的值列举出来也是一种办法。
type boolean=(false,true); 。
• 你也可以直接定义一个变量:
var c:(false,true);
var d:-10..10;
• 枚举类型本无操作符,之所以(true and false)
会得到false是因为系统预先定义了and操作符。

第七章
第八章 数组集合文件记录指针
• 数组类型 • 对文件进行操作
• 字符串是一种数组 • 标准文件类型子程序
• 字符串和字符数组的区别 • 文件指针
• 二维数组 • 记录类型
• 数组常量 • 记录类型嵌套
• 集合类型 • 使用记录类型
• in(属于)运算符 • 指针类型
• 文件类型 • 指针数组(线性列表)
• 文本文件类型 • 类型的嵌套

目录
数组类型
• 要一下子输入100个数据再把它们全部输出怎么办?定
义100个变量?你可以使用数组一下子定义100个变量,
这100个变量是一个编组,拥有同一个变量名称。
• 使用array和of关键字定义数组变量。使用方括号使用它。
program shu_zu;
var a:array[1..100]of integer;{方括号里的东西叫做下标}
i:integer;{下标必须是子界类型}
begin
for i:=1 to 100 do readln(a[i]);
for i:=1 to 100 do writeln(a[i]);
end.

第八章
字符串是一种数组
• 系统是这么定义字符串类型的:
• type string:array[0..255]of char;
• 然后你就会使用它:
• var str1:string;
• 如果你觉得字符串不够长,你也可以自己定义:
• var str2:string[65536];
• 有关字符串的子程序,请参见附录“PASCAL
字符串操作教程”。

第八章
字符串和字符数组的区别
array of char string

不能直接读入、输出 可以直接读入、输出

不能进行整体赋值 可以进行整体赋值

位数可以定义很大 位数最多255位

没有标准函数、过程 有标准函数、过程

第八章
二维数组
• 如果你要建立一个表格,每个格子里存
储一些数据,你可以定义二维数组:
var a:array[1..10,1..10]of integer;
• 然后这样使用它:
i:=a[2,3];
• 你还可以定义更高维数的数组,具体方
法就不多说了。

第八章
数组常量
• 毛主席曾经说过,常量是一种很重要的东西。
• 数组常量可以在定义的时候赋值:
const a:array[1..3]of integer=(1,2,3);
const b:array[1..2,1..2]of char=((1,2),(1,2));
• 你理解的,常量的值是不可改变的。
• 事实上我不建议使用常量数组那是因为我觉得
数组的信息比较多写在程序里再改比较麻烦,
正确的方法是把大量数据存储在文件中后再提
取。有关文件的内容将在这章介绍。

第八章
集合类型
• 不用多说,正常情况下大家编程用不着集合类
型。如果你念过高级的脑残学大概会知道集合
是何种玩应。
type set10=set of 1..10;
var a:set10;
var b:set of char;
• (注意,不能定义set of integer,integer有
65536种,貌似256种以上的都不能定义)

第八章
in(属于)运算符
• 除了>,<,=,+,-,*等运算符以外,使用in
运算符可以判断一个元素是否属于一个集合。
• 那么,如何添加一个元素到集合里呢?
var a:set of char;
begin
a:=[1,2,3];
a:=a+[4];
end;
• 你也可以自己把它写成子程序后调用。

第八章
文件类型
• 如果你家内存只有64K而硬盘有10T,那么把
数据全部存在文件里而不是直接在内存中算可
以节省大量钞票。
• 除此之外,你也不想你的程序只能在内存里玩
玩吧?如果能操作文件,你就可以获得更多信
息并存储更多信息,毕竟绝大多数电脑都是有
硬盘的。
• 不多说,先看看如何定义文件的:
var f:file of word;{还记得word是如何定义的?}

第八章
文本文件类型
• SYSTEM单元库中预定了text类型:
type text=file of char;
• 我们可以定义一个文本文件变量:
var t:text;
• 使用一个文件时,我们必须先给定一个文件的文件名:
assign(t,'c:\86.txt');{这样文件变量t和c:\86.txt就挂钩了}
• 然后必须打开文件:
reset(f);{读文件}
• 或者这样打开:
rewrite(f);{写文件}

第八章
文本文件类型
• 然后就可以操作文件了,别忘了操作完关闭文件:
• close(f);
• 文件类型其实是一种记录类型(等会马上将),它存
储了文件名,文件句柄,文件指针以及文件状态等信
息。
• assign();的作用其实是调用Windows API创建文件句柄
并将其值放到内存里。
• 本人强烈建议打开文件后的操作要尽量少,操作完立
刻关闭文件,操作时尽量不要使用readln();等待外部读
入数据,因为文件一旦打开在关闭在之前不能被其它
程序使用。如果想再次操作文件,关闭可以再次打开
它,我表示真心不麻烦。
第八章
对文件进行操作
• file of char和file of word有什么区别呢?区别在于操作
文件的方式和效果不同。
• 怎么操作呢?
• writeln(f,'one');
• readln(f,ch);
• 平时我们用writeln不加f,是因为系统已经默认输出内
容到屏幕。(屏幕也是一种文件句柄,一般句柄号是
26?)
• 你用了file of char那么writeln();或readln();的变量就用
char,integer就用integer,你理解就行。

第八章
标准文件类型子程序
• SYSTEM单元库中,除了assign();,reset();,
rewrite();,close();,writeln();,readln();等子程序免
费使用以外,还可以使用erase();删除文件,rename();
重命名文件,以及append();以末尾添加数据的方式打
开文件。这些子程序有些是有返回值的,如果操作失
败则返回值不是0。
• 重点介绍一下eof();和elon();,这两个子程序是用来判
断文件是否结束以及行是否结束的,返回值为bollean
类型。如果文件指针指向#26(文件结束)或者
#13#10(行结束)则会返回true。

第八章
文件指针
• 用append(f,str1);设置文件路径时,系统会给内存分配
一个整型变量用来存储文件读取的位置。
• 用reset(f);或rewrite(f);打开文件时,位置会被设置0,
即文件开头。
• 用writeln(f);和readln(f);读写文件时,值会增加。值的
大小就是已读取的字节数(你理解的-_-!)。
• 接着你可以用i:=filepos(f);获取这个变量的值,保存这
个位置。
• writeln();或readln();后,直接用seek(i);可以回到原来
那个保存的位置。你也可以直接用比如seek(100);跳过
100字节到文件中间读取。不过别取太大,否则程序会
崩溃。你可以用filesize();获取文件大小然后再seek();。

第八章
记录类型
• 之前我们说过,文件类型其实是一种记录类型,
那什么是记录类型呢?
• 在C语言中,记录类型又叫做结构类型。依照
我的理解,记录类型就是一组类型。先看看如
何定义一个记录类型吧:
var r:record
a:integer;
b:boolean;
c:char;
end;
第八章
记录类型
• 注意,record后面是没有分号的,也就是说,从var到
end;是一条语句。
• 上面的语句其实是定义了三个变量,分别为r.a,r.b和
r.c,它们分别为整数类型,布尔类型和字符类型。
• 有了记录类型,你就可以定义一些复杂的类型了:
type rd=record
i:integer;w:word;end;
• 接着你就可以定义这个类型的变量:
var rd1,rd2:rd;
• 最后使用变量:
rd1.i:=123;rd2.w:=45;{使用句号来使用变量}
第八章
记录类型嵌套
• filerec.inc源码中关于filerec的文件核心类型的定义
type FileRec = Packed Record
Handle : THandle;{记录类型}
Mode : longint;
RecSize : SizeInt;{type SizeInt=integer}
UserData : array[1..32] of byte;
name : array[0..255] of char;
End; :
• 从上面定义中你还可以发现,THandle类型也是记录
类型,也就是说记录类型可以嵌套,只要用多个句号
就可以了,如a.b.i等。
第八章
使用记录类型
• 不能writeln();一个记录类型,因为
SYSTEM单元库里没有定义。
• 可以直接给一个记录类型赋值,只要赋
值类型相同,如:
var a,b:record i:integer;end;
a:=b;
当然也可以a.i:=b.i;

第八章
with操作符*
var i:integer;
var rd:record i,j:integer;end;
with rd do
begin
i:=10086;j:=123;
end;
• 看过就结束,不必多纠结,本人还是建议使用句号,
结构清晰。
• 实际上rd.i和i不是同一个变量,如果同时定义了rd.i和i,
那么在使用with的时候with里默认用的是rd.i,你理解
的作用域问题。当然with也可以嵌套使用。

第八章
指针类型
• 指针类型在C语言中又叫做引用类型。
• 指针类型是一种很烦的类型。
type point=^integer;
• 我们知道,内存是计算机里面的一块砖头,这块砖头
是由无数个俄罗斯方块拼起来的,每个俄罗斯方块都
有自己的编号并且可以刻上一些数字。当我们定义一
个变量时,系统会自动分配一个俄罗斯方块给你用来
存储数据。由于定义变量必须在程序一开头进行,如
果你一开始并不知道自己要用多少变量就很麻烦。
• 能不能在程序运行的时候再分配俄罗斯方块而不是一
开始就全部分配好呢?

第八章
指针类型
• 虽然我觉得写程序基本不需要指针,而线性列表又涉
及算法,但是我觉得简单介绍一下这一块内容还是有
必要的。省的到时候有人问我“^”和“@”是什么的时
候我就哭了。
• 指针类型用来存储俄罗斯方块的号码。
• 比如我定义一个指针类型变量p和一个整型变量a:
var p:^integer;a:integer;
• 然后赋值:
a:=1;p:=@a;
• 在内存的某个俄罗斯方块(比如10086号俄罗斯方块)
中存储着变量a的值“1”,接着使用“@ ”符号就可以
获得a的值的号码,即10086,所以p=10086。
第八章
指针类型
• 用CTRL+F7跟踪变量p,然后用Debug-watch命令和
F8单步调试我们可以发现p的值实际可能是0x409010,
这就是内存中的位置了。
• 接着,我们就可以使用“^”操作符获取a的信息了:
• writeln(p^);
• p是指针类型无法直接用writeln();输出,但是p^是整型
类型所以可以输出,它的值就是p所指向的俄罗斯方块
里的内容。
• 当然,如果有var b:integer;,那么你可以直接b:=p^;。
• 同样,如果有var q:^integer;,那么也可以q:=p;。
• 注意,使用q:=p;和q^:=p^;是不同的,一个改变的是q,
一个改变的是q指向的俄罗斯方块(比如a)。
第八章
指针类型
• 指针变量也有自己的俄罗斯方块号码,它和其
它变量不同的只是它存储的数据也是一个俄罗
斯方块号码。
• 在未给p赋值之前直接用p^会爆掉。(因为计
算机不知道p指向谁。。一般来说计算机申请
使用一个俄罗斯方块时会把它的值设置为0,
即使是指针变量也是如此,所以你又时会发现
计算机游戏中的“该内存不能为read
0x00000000”就是因为没给p赋值然后直接调
用p^,而0号俄罗斯方块是不存在的)

第八章
指针类型
• 虽然p:=@a;可以把a的俄罗斯方块号赋给p,但是我们
想要使用一个新的俄罗斯方块可以这样:
new(p);
• 这条语句是向系统申请使用一个新的俄罗斯方块并把
方块号给p。这个值是动态的,只要系统中还有俄罗斯
方块可以用(内存没满)你就可以申请到。
• 然后改变这个俄罗斯方块的内容:p^:=123;
• 同样道理如果不需要用了就释放掉:
dispose(p);
• 不释放也可以,不过这样你的内存会越来越少,到最
后不够用就爆掉了。不用定义a就可以用p^是很开心的。

第八章
指针数组(线性列表)
• 讲了这么多,那么指针类型到底有什么用呢?
• 前面说到如果你一开始并不知道自己要用多少
变量就很麻烦。
• 特别是一开始需要定义一个很大的数组,需要
很多内存的时候,或者你需要定义好多好多个
数组的时候,或者你不知道数组应该弄多大
(太大浪费内存,太小怕不够用)的时候,指
针变量就来了。
• 我们知道申请一个俄罗斯方块不难,用new();
就行。实际上申请一堆俄罗斯方块也不难。
第八章
指针数组(线性列表)
• 还记得记录类型吗?记录类型和指针类型嵌套使用的
时候有意想不到的效果:
type point:^record d:real;n:point;end;
var p:point;
• 如果一个指针变量指向另一个指针变量指向另一个指
针变量。。。。。。那么指针变量要存储下一个指针
变量的俄罗斯方块号,要存储多余的数据就不行。如
果我们把一个指针变量和一个实型变量捆绑成一组,
那么我们每次就能多存一个实型变量的数据了。
new(p);p^.d:=794.624;
new(p^.next);p^.next^.d:=543.234;

第八章
指针数组(线性列表)
• 别急,慢慢看,一定要理解才能懂得指针到底是神马
东西。
• 一般人都是先new(q);一下然后直接p^.next:=q;也可以,
然后可以再new(q);或者q^.next:=q等等。
• 之前说过指针变量一开始其实不是0,而是NIL,叫做
空。值为NIL的指针即没赋值的指针叫做空指针,你也
可以直接把NIL赋给一个指针变量。
• 我自己写了一个单元库用来创建动态数组,详细请见
附录“线性列表动态数组单元库”。反正只要能用用
就行不必纠结。

第八章
类型的嵌套
• 数组类型可以用集合类型、记录类型等作为基
类型。
• 记录类型的某个基类型也可以是数组类型。
• 记录类型的某个基类型可以是指针类型,这个
指针类型甚至可以指向这个记录类型。
• 总之不管怎么样都可以,你要你会用且用的爽。
var a:array[1...100]of record i:record
j:integer;end;end;

第八章
类与对象类型*
• 懒得介绍了,出门右转Delphi。
• 对象类型(记录类型的升级版):
object
end;
object(<父对象>){派生}
end;

第八章
附录
• ASCII和EASCII码表 • Pascal图形操作教程
• 基本符号 • Pascal退出语句用法
• 常用关键字列表 • system.fpd
• 常用子程序列表 • func.inc
• Pascal错误码表 • 线性列表动态数组单
• 四种参数传递方式 元库
• Pascal字符串操作教程 • 排序算法

目录
ASCII和EASCII码表
• http://www.asciitable.com/
• http://www.ascii-code.com/
• 参见“附录”文件夹“user.pdf”的64页。

附录
基本符号
• ABCDEFGHIJKLMNOPQRSTUVWXYZ
• abcdefghijklmnopqrstuvwxyz
• 0123456789
• +-*/=<>><<=>=()[]{}:=.,:;'..^@$%

附录
常用关键字列表
• 打进去白色的都是关键字。
• 参见“附录”文件夹“Pascal关键
字.xls”。
• 参见“附录”文件夹“user.pdf”的128页。

附录
常用子程序列表
• http://www.freepascal.org/download.var
• 自行下载fp,在doc,help文件夹里自己
找子程序。
• 也可以直接下fp的源码,然后在source文
件夹里直接看源码(教程都叫过你了,
你自己慢慢看吧)。
• 参见“附录”文件夹“rtl.pdf”。

附录
Pascal错误码表
• http://www.hu.freepascal.org/lists/fpc-
pascal/2000-September/000087.html
• 参见“附录”文件夹“Pascal错误码
表.txt”。
• 还有一些其它蛋疼的错误,比如你可以
试试Uses System,然后会很蛋疼。

附录
Pascal编译指令
• http://www.freepascal.org/docs-
html/user/usersu68.html
http://www.freepascal.org/docs-
html/user/user.html
• 参见“附录”文件夹“chart.pdf”。

附录
四种参数传递方式
• Pascal的参数传递都是传值的。
• 参见“附录”文件夹“四种参数传递方
式.doc”。

附录
Pascal字符串操作教程
• 参见“附录”文件夹“Pascal字符串操
作教程.txt”。

附录
Pascal图形操作教程
• 参见“附录”文件夹“Pascal图形操作
教程.txt”。

附录
Pascal退出语句用法
• 参见“附录”文件夹“Pascal退出语句
用法.txt”。

附录
system.fpd
• 参见“附录”文件夹“system.fpd”。

附录
func.inc
• 参见“附录”文件夹“func.inc”。

附录
线性列表动态数组单元库
• 参见“附录”文件夹“ARRNODE.pp”。

附录
排序算法
• 目标:将一个数组升序排列或降序排列。
• 参见“附录”文件夹“排序”文件夹。

附录
后记
• 随着编程水平的逐渐提高,渐渐地你会发现用Pascal
语言写一个魔兽争霸从理论上是不成问题的(在屏幕
上画点),然而实际操作时会发现难度很大,因为画
点的速度太慢了。
• 使用Driect X是一个快速画画的方法。Direct X是一堆
dll,它提供了直接操作底层硬件(屏幕)的子程序。
• 当然,用Pascal语言写office系列软件还是很累的,要
创建一个比如窗口没有c面向对象编程语言方便。不过,
使用Pascal解决数学问题或者研究算法还是很理想的。
• Pascal语言也是一种和伪代码最相似的语言。

目录
谢谢!
• 如果你想在本教程基础上修改,请不要
删除或修改第一张幻灯片-_-!。

Das könnte Ihnen auch gefallen