delphi语法基础--过程

本文介绍了Delphi编程中的过程,包括过程的定义、参数类型(值形参和变量形参)及其调用机制。此外,还讨论了变量的作用域(全程变量和局部变量),特别是它们如何影响程序中的数据交互。最后,文章提到了递归调用的概念及其在解决问题时的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给某个语句序列组成的子程序赋于一个标识符。程序中凡是需要出现这个语句序列的地方,可以简单的写上该子程序的标识符。这样完成一个操作的子程序称为过程。过程说明。
一、过程
1、过程定义由过程首部和过程体组成,其形式如下:
     procedure 过程名(形式参数表);   { 过程首部 }     
       局部变量说明;
      begin
       执行语句;
        ……             过程体
     end;
例1:定义过程求n!。
procedure jc(n:integer);             
   var k:integer;                 
  begin                             { 变量t在主程序中说明 }
   t:=1; for k:=2 to n do t:=t*k;  { 最后由t将n!值返回调用程序 }

end;                               
   过程首部,以保留字procedure开头。圆括号内为形参表。无参数时,形参表可省略。定义的过程名不能再做其它变量名、数组名、过程名等。

    形参有值形参和变量形参。如:procedure sub(x,y:integer; var k:real); 

其中,x,y为值形参,k为变量形参。

除函数首部和过程首部的句法略有差别外,函数体和过程体完全相同。函数返回一个函数值,过程则能完成一系列各种操作。函数的调用方式出现在表达式中,而过程调用是一句独立的语句。与函数不同,不能给过程名赋值。

 

二、变量及其作用域

1.全程变量的作用域
  全程变量是指在程序开头的说明部分定义和说明的量。它的作用域分为两种情况:
(1)在全程变量和局部变量不同名时,其作用域是整个程序。
(2)在全程变量和局部变量同名时,全程变量的作用域不包含同名局部变量的作用域。

2.局部变量的作用域
  凡是在子程序内部使用的变量,必须在子程序中加入说明。这种在子程序内部说明的变量称为局部变量。局部变量的作用域是其所在的子程序。形式参数也只能在子程序中有效。因此也属于局部变量。局部变量的作用域分为两种情况:
(1)当外层过程的局部变量名和嵌套过程中的局部变量不同名时,外层过程的局部变量作用域包含嵌套过程。
(2)当外层过程的局部变量名和嵌套过程内的局部变量名同名时,外层局部变量名的作用域不包含此过程。

   引入局部变量可以节省内存空间,且便于结构化程序设计。在某些程序中,为了使变量间不互相干扰,一般采用局部变量。如变量间需某种联系时,则可选择全程变量或形参。

 

三、参数的调用

函数调用或过程调用的执行步骤分为以下几步:
    实参和形参结合→执行函数或过程体→返回调用处继续执行
 
  函数或过程说明的形参表对函数或过程体直接引用的变量进行说明,详细指明这些参数的类别、数据类型要求和参数的个数。函数或过程被调用时必须为它的每个形参提供一个实参,按参数的位置顺序一一对应,每个实参必须满足对应形参的要求。
 
  形参可分为四类:值形参,变量形参、函数形参和过程形参。实参也可分为四类:值实参,变量实参、函数实参和过程实参。
 
1.值参数
  值参数是形式参数表中前面没有var,后有类型说明的参数。

如:function fac(x:integer):integer; 它类似过程和函数的局部变量,仅为过程和函数的执行提供初值而不影响调用时实际参数的值。在调用过程或函数时,值参数所对应的实际参数必须是表达式。实参必须和形参赋值相容。

var a:integer;

procedure s(b:integer);   { b为值形参 }

begin b:=b+5; writeln('b=',b) end; 

begin 

a:=10; s(a); writeln('a=',a)

end.

运行结果:

b=15   { 过程中输出的值形参b的值 }

a=10   { a为实参,并没有因调用过程而改变其值,值形参b的值的改变并不影响相应实参a的值。}  

 

2.变量参数
  形式参数表中前面有var后由类型的参数。如果需要子程序向调用程序返回值时,应采用变量参数。变量参数要求它的实参是和它同一类型的变量。因为在子程序执行时,遇到对相应形参的引用式定值,就是对相应实参的引用式定值,即对形参的任何操作就是对实参本身的操作。

var a:integer;

procedure s(var b:integer);   { b为变量形参 }

begin b:=b+5; writeln('b=',b) end; 

begin

a:=10; s(a); writeln('a=',a)

end.

运行结果:

b=15   { 过程中输出的变量形参b的值 }

a=15   { b将值返回主程序调用处,对变量形参b的引用或赋值就是对相应实参a的引用或赋值。}
 
例4:定义过程swap,完成变量 a和b的交换。

程序一

var a,b:integer;

procedure swap;

  var t:integer;                { 通过全程变量将过程中的值传回主程序 }

  begin t:=a; a:=b; b:= t  end;

begin

  a:=10; b:=20; writeln('a=',a, '  b=',b);

  swap;  writeln('a=',a, '  b=',b);

end.  

程序二

var a,b:integer;

procedure swap(var m,n:integer); { 通过变量参数将过程中的值传回主程序 }

  var t:integer;

  begin t:=m; m:=n; n:=t  end;

begin

  a:=10; b:=20; writeln('a=',a, '  b=',b);

  swap(a,b);  writeln('a=',a, '  b=',b);

end.

程序三

var a,b:integer;

procedure swap(m,n:integer);   { 本程序不能完成两个变量值的交换,为什么? }

  var t:integer;

  begin t:=m; m:=n; n:= t  end;

begin

  a:=10; b:=20;  writeln('a=',a, '  b=',b);

  swap(a,b);   writeln('a=',a, '  b=',b);

end.

m,n为值形数,它类似局部变量,仅为过程和函数提供初值而不影响调用时实参的值。

 

例5:设计一个过程,将数组中的元素从大到小排列。

type atype= array[1..10] of integer;

var a: atype;                   { a 为数组类型 }

    n:integr;

procedure sort(var b: atype);   { 变量形参b为数组参数 }

  var i,j,k:integer;

  begin

  for i:=1 to 9 do

for j:=i+1 to 10 do

if b([i]<b[j] then begin k:=b[i]; b[i]:=b[j]; b[j]:=k  end

end;

begin                                { 主程序 }   

for i:=1 to 10 do  read(a[i]);

sort(a);                           {  过程调用,实参a为数组类型 }

for i:=1 to 10 do  write(a[i], '  ')

end.

过程中对变参b的操作就是对实参a的操作。当形参为数组类型时,必须用类型名进行定义。不能写成: procedure sort(var b:array[1..10] of integer);

 

四、程序的嵌套和超前引用

1、  程序的嵌套

    一个过程或函数调用另一个过程或函数,称为过程与函数的嵌套。嵌套是一层套一层的程序结构,从外向内逐层相包。注意:

①内、外层不能相互交叉,内层必须完全嵌套在外层之中;

②一般情况下,过程或函数内部需要使用的变量应在内部进行定义。外层不能访问内层所定义的变量。
 

2、  超前引用

有时程序在并列的函数或过程需要相互调用,或前面定义过的过程或函数需调用后面定义函数或过程。这就违反了标识符必须先定义后使用的原则。解决这个问题的方法是适当处理后,超前引用。

 例6、设有下列函数和过程:

  procedure a(m,n:integer);

{ a的过程体 }

procedure b(x:integer);

{ b的过程体 }

function (s:integer):integer;

{ c的函数体 }

  如果a调用b和c,而b和c 又调用a,写出这些函数和过程的说明次序。

 解:

procedure b(x:integer); forward;          { 过程b的首部提前 }

上一页  [1] [2] [3]  下一页

function c(s:integer):integer; forward;   { 函数c的首部提前 }

procedure a(m,n:integer);

{ a的过程体 }

procedure b;           { 过程b被提前引用后,此处去掉形参表 }       

{ b的过程体 }

function c;            { 函数c被提前引用后,此处去掉形参表和函数类型 }

{ c的函数体 }

 

五、递归调用
    如果一个过程或函数又直接或间接调用自身,称为递归。

使用递归求解问题,一般可将一个比较大的问题层层转化为与原问题类似的、规模较小的问题进行求解,最终达到对原问题的解决。

递归的关键在于找出递归方程式和递归终止条件。

例7、求n!。
     阶乘的算法可以定义成函数:
              n*f(n-1) (n>0)
       f(n)=
              f(n)=1   (n=0)

使用递归定义,把求n!转化为求(n-1)!* n的问题,而求(n-1)!又转化为求(n-2)!的问题,……,最后归结为求0!的问题,由0!=1有一步步求出1!,2!,……,直到求出n!。当n=0时,f(n)=1,是递归结束的条件。
   var n,s:integer;
   function fac(a:integer):integer;
     begin
       if a=0 then fac:=1
              else fac:=a*fac(a-1);
     end;
   begin
     readln(n);
     s:=fac(n);
     write(n, '!= ',s)
   end.

例8、求裴波那契数列的第n项。
     定义: f(n)=f(n-1)+f(n-2);  f(0)=0;  f(1)=1;

var n:integer;
    function f(n:integer):longint;
     begin
       case n of
          0: f:=0;                { 递归结束条件 }
          1: f:=1;
          else f:=f(n-1)+f(n-2) { 递归调用 }
       end
     end;
   begin 
     write('n:'); readln(n);
    writeln(f(n))
  end.

例9、倒序输出以“.”结尾的字符串,如输入abcdef@sina., 输出anis@fedcba。 
   procedure down;
     var c:char;
     begin
       read(c);
       if c<>'.' then down  else  exit;
       write(c)
     end;
   begin
     down; writeln
   end.

递归算法一般用于解决三类问题:
    ⑴ 数据的定义形式是按递归定义的。比如阶乘的定义。这类递归问题往往又可转化成递推算法,递归边界作为递推的边界条件。
    ⑵ 问题解法按递归算法实现的。例如回溯等。
    ⑶ 数据的结构形式是按递归定义的。如树的遍历, 图的搜索等。

    递归算法解题简洁,但其运行效率较低。在递归调用的过程中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出。一个问题的求解如果既可以用递归算法,也可以用递推算法,则往往用递推算法,因为递推的效率比递归高。

 

上一页  [1] [2] [3] 

<script src="/adfile/Contact.js" type="text/javascript"></script><script src="/adfile/Contact.js" type="text/javascript"></script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值