C++程序设计课件 设计制作:徐龙琴 2
? 函数 的 概述 (产生、概念、分类 )
? 函数 的 定义, 声明 和 调用
?内联 函数
?重载 函数
?函数 的 嵌套调用 及 递归调用
? 变量 及 函数 的 存储类型
本章要点:
C++程序设计课件 设计制作:徐龙琴 3
§ 函数的概述
在早期的程序设计中,人们发现程序中 经常 会 有大量重复 的代码, 为了
减少程序的书写量,常常 把 这些重复的 代码 从程序中 抽出来, 使其成为 一个独
立的 程序单位 (子程序)并为其取一个名字,程序中 需要 这些代码的地方用相
应的名字来取代,即 调用 相应的子程序(又叫 子函数 )。
一个 C++程序 里 包含 一个 主函数 (即 main函数) 和 若干个
其它函数 。由 主函数调用其它函数,其它函数之间也可以互
相调用 。
我们用下图来说明 程序, 函数 以及 语句 的关系:
C++程序设计课件 设计制作:徐龙琴 4
?函数, 就是 能够完成一定功能的程序段,由 函数头和函数体
组成
C++程序设计课件 设计制作:徐龙琴 5
?函数分类:
? 库函数, 所谓库函数也称标准函数,由 C++系统提供。能 完
成一定的功能,其已编译为机器码。在,h文件中提供了库函
数定义的形式(原型)。
? main函数,每个 Project(工程或项目) 有且只有一个 main() 。 执
行 C++程序,也就是执行相应的 main()函数。
? 自定义函数,完成用户所需的功能。
注意,函数可以被一个函数调用,也可以调用另一个函数,C++程序
中调用函数之前,首先要对函数进行定义。
C++程序设计课件 设计制作:徐龙琴 6
§ 函数的定义、声明和调用
一 函数的定义格式,返回值类型 函数名(形式参数表)
{ 函数体;
}
? 返回值类型,为 任意 的 C++类型, 也 可 以是 void,它表示函数没
有返回值。 也可 以 缺省,这时系统当 int解释。
函数名,为函数取得名字,应符合标识符的命名规则
C++程序设计课件 设计制作:徐龙琴 7
形 式 参 数表,有 0个或 多个 形参, 用于 向函数传送数值或从函数带
回数值,每个 参数 都有 自己的 类型 多个形参说明用逗
号隔开。 形参说明的格式为,类型 形参名
如果参数表列中参数个数为 0,我们称之为 无参函数,
无参函数可以定义为:
返回类型 函数名 ( ) 或 返回类型 函数名 (void)
{…} {…}
函数体, 为一个复合语句。它可以包含 return语句(用于该函数
的结束控制)。
return语句 的两种格式,1) return (表达式) ;
或 return 表达式 ;
2) return;
C++程序设计课件 设计制作:徐龙琴 8
1,void Hello( )
{
cout<<" Hello,world"<<endl;
}
2.求 阶乘 函数 facto的 定义 。
long facto ( int x )
{ long y;
for (y=1; x>0; --x)
y*=x;
return (y);
}
函数名
形式参数表列
函数体
函数返回
函数 定义实例,
C++程序设计课件 设计制作:徐龙琴 9
例 3,求两个浮点数和的函数
double sum (double x,double y)
{ double z;
z = x + y;
return z;
}
double sum ( x,y)
double x;
double y;
{ double z;
z = x + y;
return z;
}
等价
C++程序设计课件 设计制作:徐龙琴 10
函数定义时注意点:
( 1) 在一个函数体内 允许有 一个或 多个 return语句,一旦执行到 其中某一
个 return语句时, return后面的语句就不再执行,直接 返回调用 位置
继续向下执行。
( 2) 不允许函数嵌套定义,即在函数定义中再定义一个函数是非法的。
( 3) 定义函数时 函数类型 的说明,应与 return中返回值 表达式的类型一致 。
如果不一致,则 以函数类型为准 。
( 4) 所有的 函数都要先定义, 后使用 (调用)。
C++程序设计课件 设计制作:徐龙琴 11
二 函数的说明(又叫函数声明):
函数声明 也称 函数模型 ( 或 函数原型 )。在主调函数中,如果 要
调用另一个函数,则 须 在本函数或本文件中的开头将要被调用的函数
事先作一 声明 。声明函数,就是告诉 编译器函数的返回类型、名称和
形参表构成,以便编译系统对函数的调用进行检查。
⒈ 函数声明 的一般 格式 为,
函数类型 函数名 (形式参数表);
例,设有一函数的定义为:
double func1(double a,int b,float c)
{函数体
}
C++程序设计课件 设计制作:徐龙琴 12
正确完整的函数声明应为,
double func1(double a,int b,float c);
也可以 写为如下形式,
double func1(double,int,float);
或写为 如下形式,
double func1(double x,int y,float z);
C++程序设计课件 设计制作:徐龙琴 13
三 函数的调用:
在 C++中,除了主函数 main由系统自动调用外,其他函数都是由主
函数直接或间接调用的。
⒈ 函数 调用格式, 函数名 (实际参数表);
? 实参, 应 该 与 函数定义中的形参表中的 形参 一一对应,
即 个数相等, 次序一致 且对应参数的 数据类型
相同 或相容 。每个 实参也可以 是一个表达式,
并且 必 须有确定的值。
C++程序设计课件 设计制作:徐龙琴 14
例,给出以下程序的运行结果
#include <iostream.h>
int func(int n);
void main()
{ int n;
cout<<"Please input n:"<<endl;
cin>>n;
cout<<"\nthe result:"<<func(n)<<endl;
}
int func(int n)
{if(n>0)
return 1;
else if(n==0)
return 0;
else return -1;
}
此程序的运行结果为:
Please input n:
2
the result:1
C++程序设计课件 设计制作:徐龙琴 15
例:函数调用:
#include<iostream.h>
int max(int a,int b,int c)
{int t;
t=a;
if(b>t) t=b;
if(c>t) t=c;
return t;}
void main()
{int x,y,z;
cout<<”Please input x y z:”<<endl;
cin>>x>>y>>z;
int m=max(x,y,z);
cout<<”The max is:”<<m<<endl;
}
此程序的运行结果为:
Please input x y z,
23 45 12
The max is:45
C++程序设计课件 设计制作:徐龙琴 16
#include <stdio.h>
int add(int,int);
void main()
{ int a,b,sum;
scanf(“%d”,&a);
scanf(“%d”,&b);
sum=add(a,b); //调用
printf(“sum=%d\n”,sum);
}
int add(int x,int y)
{ int z;
z=x+y;
return z;
}
原型:说明函数的类型、名称、参数
类型及参数个数,以便编译过程在函
数调用中对照检查。
定义:说明函数的功能,实现方法。有
代码内容。编译系统将全面检查该函数
的语法,并为其准备存储空间。
C++程序设计课件 设计制作:徐龙琴 17
⒉ 函数 调用过程,
当调用一个函数时,整个调用过程 分为 三步 进行:
第一步,是参数传递。
第二步,是函数体执行。
第三步,是返回,即返回到函数调用的位置。
⑴ 参数传递
参数传递, 即 实参向形参传递信息,使形参具有确切地含义(即具
有对应的存储空间和初值)。这种传递 又分为 两种不同
的方式:一种是 按值 传递,
另一种是 地址传递 或 引用传递 。
C++程序设计课件 设计制作:徐龙琴 18
① 按 值传递
按值传递方式进行参数传递的 过程为,
首先, 计算 出 实参 表达式 的值,
接着, 给 对应的 形参 变量 分配 一个 存储空间 (该空间的大小等于
该形参类型的长度),然后 把已求出的 实参 表达式 的值 一一
存入 到为 形参 变量分配 的存储空间中,成为形参变量的初值,
供被调用函数执行时使用。
#include <iostream.h>
void swap(int,int);
void main()
{int a=3,b=4;
cout<<"a="<<a<<",b=,
<<b<<endl;
swap(a,b);
cout<<"a="<<a<<",b="<<b
<<endl; }
例,按值传递。
void swap(int x,int y)
{int t=x;
x=y;
y=t; }
此程序的运行结果为:
a=3,b=4
a=3,b=4
C++程序设计课件 设计制作:徐龙琴 19
#include <stdio.h>
void main( )
{ int a,b,c;
int max (int x,int y);
printf(“Enter a,b \n”);
scanf(“%d,%d”,&a,&b);
c = max( a,b );
printf(“Max = %d”,c);
}
int max (int x,int y)
{ int z;
z = x > y? x, y ;
return ( z );}
形式参数, 是用‘,’
分开的一组变量,用来
接收调用时传入的数据
函
数
调
用
实际参数,是用
‘,’分开的一组
变量,用来将其值
传递给形式参数
例,求两个变量的最大值。 此程序的运行结果为:
Enter a,b
23,12
Max =23
C++程序设计课件 设计制作:徐龙琴 20
◆ 形式参数, 指 定义函数时 函数名后面括弧中的变量名,
简称, 形参, 。
◆ 实际参数, 调用另一个函数时,函数名后面括弧中的参
数,简称, 实参,
◆ 实参 可以是 常量, 变量 或 表达式,但 要求它们有确
定的值 (若形参为数组名,则传递的是数组的首地
址 )
◆ 未出现函数调用时,形参并不占存储单元。 只有在
发生函数调用时,被调函数中的形参才被分配内存
单元 。调用结束后,形参所占内存单元被释放
◆ 实参 与 形参 的 类型应相同
形式参数和实际参数,
C++程序设计课件 设计制作:徐龙琴 21
② 地址传递
地址传递,如果在 函数定义时 将 形参 的 类型 说明成 指针 (*),对这样的
函数进行 调用时 就需要指定 地址值形式的实参 。 这 时的参数
传递方式 即为地址传递方式 。这种 地址传递与上述的按值传
递不同,它把实参的存储地址传送给对应的形参,从而使得
形参指针和实参指针指向同一个地址。因此,被调用函数中
对形参指针所指向的地址中内容的任何改变都会影响到实参
C++程序设计课件 设计制作:徐龙琴 22
例,地址传递。
#include "iostream.h"
void swap(int *,int *);
void main()
{int a=3,b=4;
cout<<"a="<<a<<",b=“
<<b<<endl;
swap(&a,&b);
cout<<"a="<<a<<",b=“
<<b<<endl;
}
void swap(int *x,int *y)
{
int t=*x;
*x=*y;
*y=t;
}
此程序的运行结果为:
a=3,b=4
a=4,b=3
C++程序设计课件 设计制作:徐龙琴 23
③ 引用传递 (引用 (&):是标识符的别名 )
引用传递, 是 在函数定义时在 形参前面 加上 引用运算符,&”。 引用只
是
某个变量或对象的“别名”,函数被调用时, 系统不会复制
实
参的副本,而是将形参“绑定”在实参上,直接对实参进行
操
作 。 引用传递时 对形参的任何操作都能改变相应的实参的数
据,使函数调用显得方便、自然
#include "iostream.h"
void swap(int &,int &);
void main()
{int a=3,b=4;
cout<<"a="<<a<<",b=“
<<b<<endl;
swap(a,b);
cout<<"a="<<a<<",b=“
<<b<<endl; }
void swap(int &x,int &y)
{ int t=x;
x=y;
y=t;
}
此程序的运行结果为:
a=3,b=4
a=4,b=3
C++程序设计课件 设计制作:徐龙琴 24
例:
#include <iostream.h>
#include <iomanip.h>
void fiddle(int in1,int &in2);
int main( )
{ int count = 7,index = 12;
cout << "The values are ";
cout<<setw(5)<<count;
cout<<setw(5)<<index<<endl;
fiddle(count,index);
cout << "The values are ";
cout<<setw(5)<<count;
cout<<setw(5)<<index<<endl;
}
void fiddle(int in1,int &in2)
{
in1 = in1 + 100;
in2 = in2 + 100;
cout << "The values are ";
cout<<setw(5)<<in1;
cout<<setw(5)<<in2<<endl;
}
此程序的运行结果为:
The values are 7 12
The values are 107 112
The values are 7 112
C++程序设计课件 设计制作:徐龙琴 25
例,用函数 facto计算 m阶乘。 函数执行过程
main ( )
{
mm = facto( m );
}
facto ( x )
{
return (y );
}
调用 返回
#include <stdio.h>
void main( )
{ int m; long mm;
long facto( int x );
scanf("%d",&m);
mm = facto( m );
printf("%d!=%ld.\n",m,mm);
}
long facto ( int x )
{ long y;
for ( y=1; x>0; --x )
y*=x;
return (y);
}
C++程序设计课件 设计制作:徐龙琴 26
§ 带默认形参值的函数
在 C++语言中 调用函数 时,通常要为函数的每个形参给
定对应的实参。 若没有给出实参,则 按指定的默认值 进行工
作。
当 一个 函数 既有 定义 又有 声明时, 形参的默认值 必须 在
声明中指定,而不能放在定义中指定。只有 当 函数 没有声明
时,才可以 在函数定义中指定形参的默认值 。
默认值的定义必须 遵守 从右到左的顺序, 如果 某个形参没
有默认值,则它左边的参数就不能有默认值。
C++程序设计课件 设计制作:徐龙琴 27
例:
void func1(int a,double b=4.5,int c=3); //合法
void func1(int a=1,double b,int c=3); //不合法
在进行函数调用时,实参 与 形参 按 从左到右的顺序进行
匹配,当 实参 的 数目 少于 形参时,如果对应位置形参又 没 有
设定默认值,就会 产生编译错误 ;如果设 定了默认值,编译
器 将 为那些 没有对应实参的形参取默认值 。
注意, 形参的默认值 可以是 全局常量, 全局变量, 表达式,
函数调用,但 不能为 局部变量 。
C++程序设计课件 设计制作:徐龙琴 28
例,带缺省形参值的函数举例
#include <iostream.h>
#include <iomanip.h>
int f(int length,int width = 2,int height = 3);
int main( )
{int x = 10,y = 12,z = 15;
cout << "Some box data is " ;
cout << f(x,y,z) << endl;
cout << "Some box data is " ;
cout << f(x,y) << endl;
cout << "Some box data is " ;
cout << f(x) << endl;
cout << "Some box data is ";
cout << f(x,7) << endl;
cout << "Some box data is ";
cout << f(5,5,5) << endl;
}
int f(int length,int width,int height)
{ cout<<setw(5)<<length
<<setw(5)<<width
<<setw(5)<<height<<' ';
return length * width * height; }
运行结果:
Some box data is 10 12 15 1800
Some box data is 10 12 3 360
Some box data is 10 2 3 60
Some box data is 10 7 3 210
Some box data is 5 5 5 125
C++程序设计课件 设计制作:徐龙琴 29
§ 内联 函数
#include <iostream.h>
int sum(int x,int y)
void main()
{ ……
sum(2,4);
……
sum(5,1);
……
sum(45,11);
……
}
例, int sum(int x,int y)
{ return (x+y);
}
函数 可 提高 程序代码的 复用度 和 可读性,
但 同时也 增加了 额外的系统 开销 。特别
对频繁调用一个小函数的程序,其 执行
效率 是 不高 的。 如何 提高工作效率 有两
种办法, 宏定义 或 内联 函数。
C++程序设计课件 设计制作:徐龙琴 30
#include <iostream.h>
#define max(a,b) a>b?a:b
void main(){
int x,y;
…
cout << max(x,y) << endl;
cout << 10+max(x,y)+z << endl;
…
}
1、宏定义,
例,
在编译宏替换时为,x>y?x:y
在编译宏替换时为:
10+x>y?x:y+z
因此, 上面的 max宏定义是不可靠的, 应该定义为:
#define max(a,b) (((a)>(b))?(a):(b))
C++程序设计课件 设计制作:徐龙琴 31
#include <iostream.h>
#define multiply(a,b) a*b
void main(){
…
cout << multiply(x+y,m-n) << endl;
…
}
例,
在编译宏替换时为,x+y*m-n
宏定义的缺点:
1)重复计算。
2)参数类型检查不足。
C++程序设计课件 设计制作:徐龙琴 32
计算机在执行一般 函数 的 调用时,无论该函数多么简单或复杂,
都要经过 参数传递, 执行函数体 和 返回等 操作,这些操作都需要一定
的时间开销。 若把一个函数 定义为 内联函数 后,在 程序 编译阶段,编
译器就 会把 每次 调用 该 函数 的地方都 直接替换为 该 函数 体中的 代码,
由此省去函数的调用及相应的保存现场、参数传递和返回操作,从而
加快整个程序的执行速度。
⒉ 内联函数, 也称为 内嵌函数 。当在一个函数的 定义 或 声明前加 上关键
字 inline则就把该函数定义为内联函数,它主要是 解决 程
序的 运行效率 。
C++程序设计课件 设计制作:徐龙琴 33
例:
#include <iostream.h>
inline int abs(int x)
{ return x<0?-x:x;
}
void main()
{ int a,b=3,c,d=-4;
a=abs(b);
c=abs(d);
cout<<"a="<<a<<",c="<<c<<endl;
} 此程序的运行结果为, a=3,c=4
在函数名前加 inline限定符:可放在定义处或说
明处,但必须放在调用之前声明。
C++程序设计课件 设计制作:徐龙琴 34
注意:
① 内联函数 可以 在一开始仅定义或声明一次, 但 必须在函
数被调用之前定义或声明 。否则,编译器不认为那是内
联函数,仍然如同对普通函数那样处理该函数的调用过
程。
② 内联函数 中 不能含有 任何 循环 以及 switch和 goto语句
③ 内联函数 中 不能 说明数组
④ 递归函数 (自己调用自己的函数) 不能定义为 内联函数
C++程序设计课件 设计制作:徐龙琴 35
§ 函数重载
⒈ 函数的重载, 又称为 函数的多态性,是 指 同一个函数名对应着多个不同
的函数 。所谓,不同,是 指 这些函数的 形参表 必须 互不相
同,或者是形参的 个数 不同,或者是形参的 类型 不同,或
者是两者都不相同,否则将无法实现函数重载。
例如,下面是合法的重载函数:
int add(int,int);
char add(int char);
double add(int,double);
float add(long float);
C++程序设计课件 设计制作:徐龙琴 36
例,重载函数应用举例
编写两个名为 add的重载函数,分别实现两整数相加、两实
数相加的功能。
#include <iostream.h>
int add(int m,int n)
{ return m+n; }
double add(double x,double y)
{ return x+y; }
void main ( )
{ cout<<add(34,12)<<endl;
cout<<add(1.3,0.96)<<endl;
}
运行的结果为:
46
2.26
C++程序设计课件 设计制作:徐龙琴 37
注意:
① 重载函数的 返回类型 可以相同, 也可以不同 。但如果仅
仅 是 返回类型不同 而 函数 名相同、形参表也相同,则 是
不合法 的,编译器会报“语法错误”。如:
int func1(int a,int b);
double func1(int a,int b);
② 除形参名外 或 返回类型 都相同的 情况,编译器不认为是
重载 函数,只 认为是 对 同一个函数 原型的多次声明 。
③ 调用重载函数 func1()时, 编译器 根 据 实参 的 个数 和
类型 对所有 func1()函数的形参一一进行比较,从而
调用 一个 最匹配的函数 。
④函数重载主要用于功能相同而参数不同的多个函数的定义。 不要将
不同功能的函数声明为重载函数,
C++程序设计课件 设计制作:徐龙琴 38
§ 函数的嵌套调用
main函数
{ ……
……
调用函数 A;
……
}
函数 A
{ ……
……
调用函数 B;
……
}
函数 B
{ ……
……
……
}
嵌套调用,在调用一个函数的过程中,又调用另一个函数
C++程序设计课件 设计制作:徐龙琴 39
例, 输入两个整数,求平方和。
#include <iostream.h>
void main( )
{ int a,b;
int fun1(int x,int y);
cin>>a>>b;
cout<<“a,b的平方和:,
<<fun1(a,b)<<endl;
}
int fun1(int x,int y)
{
int fun2(int m);
return (fun2(x)+fun2(y));
}
int fun2(int m)
{
return (m*m);
}
运行结果:
3 4
a,b的平方和,25
C++程序设计课件 设计制作:徐龙琴 40
§ 函数的递归调用
⒈ 递归调用, 一个函数直接或间接地调用自身,这种现象就是函
数的递归调用。它是函数嵌套调用的特例。
⒉ 递归调用有两种方式:
① 直接递归,即在一个函数中调用自身,
② 间接递归,即在一个函数中调用了其他函数,而在该其
他函数中又调用了本函数。
⒊ 递归调用作用:
可将一个复杂问题分解为一个相对简单且可直接求解的
子问题(“递推”阶段);然后将这个子问题的结果逐层进
行回代求值,最终求得原来复杂问题的解(“回归”阶段)。
C++程序设计课件 设计制作:徐龙琴 41
在 以下三种情况 下,常 常 要 用到递归,
定义是递归的:
如,
1 n=0,1
n*(n-1)! n>1
斐波那契数列
1,1,2,3,5,8,……
数据结构是递归的:如链表、树 ……
问题的解法是递归的:汉诺塔问题,
n!=
C++程序设计课件 设计制作:徐龙琴 42
递 归 模 型
f(n)=1 当 n=1
f(n)=n*f(n-1) 当 n>2 时{
递归程序通式
int digui(int n)
{ if(n= =1)
return 1;
else
return (n*digui(n-1));
}
或 int digui(int n){ int r;
if(n= =1) r=1;
else r=(n*digui(n-1));
return r;}
C++程序设计课件 设计制作:徐龙琴 43
例,求 12 + 22 + 32 + ‥‥ ‥ n 2 之和
算法分析:
要求 12 + 22 + 32 + ‥‥ ‥ n 2 之和只需要求出
12 + 22 + 32 + ‥‥ ‥ (n- 1) 2之和,‥‥ ‥ 并且它
门的解法相同,故可采用递归来实现。
解,int digui(int n)
{ if(n= =1) return 1 ;
else return(n*n+digui(n-1));
}
C++程序设计课件 设计制作:徐龙琴 44
例:求数列,1,1,2,3,5,8,13,21,……第 n项
建立问题的 递归定义,
f(n)=1 当 n=1或 n=2 时
f(n)=f(n-1)+f(n-2) 当 n>2 时
递归结束条件
递归初试条件
程序:
int f ( n )
{ if (n==1||n==2) return (1);
else return ( f(n-1) + f(n-2) );
}
C++程序设计课件 设计制作:徐龙琴 45
int facto ( int n )
{ int s;
if ( n = = 1 )
s = 1;
else
s = n * facto(n-1);
return (s);
}
facto ( int n )
{ int s;
if ( n == 1 )
s = 1;
else
{ s = facto (n-1);
s = n*s;
}
return (s);
}
等价于
n! = 1 当 n = 1 时
n! = n * (n-1)! 当 n > 1 时
例:用递归函数求 n!的子函数 。
C++程序设计课件 设计制作:徐龙琴 46
facto(int n)
{ int s;
if(n= =1)
s = 1;
else
{ s=facto(n-1);
s=n*s;
}
return(s);
}
facto(int n)
int s;
if(n= =1)
facto(int n)
{ int s;
if(n= =1)
s = 1;
else
{ s=facto(n-1);
s=n*s;
}
return(s);
}
s=facto(n-1)
facto(int n)
int s;
if(n= =1)
facto(int n)
{ int s;
if(n= =1)
s = 1;
else
{ s=facto(n-1);
s=n*s;
}
return(s);
}
s=facto(n-1)
facto(int n)
{ int s;
if(n= =1)
s = 1;
else
{ s=facto(n-1);
s=n*s;
}
return(s);
}
facto(int n) facto(int n)
int s; int s;
if(n= =1) if(n= =1)
s=facto(n-1)
s = 1
return(1)
s=n*s=2*1
return(2)return(6)
s=n*s=3*2s=n*s=4*6
return(24)
1 2 3
4
321
N=4 N=3 N=2 N=1
C++程序设计课件 设计制作:徐龙琴 47
§ 变量的作用域与存储周期
变量 有效的范围 ( 称为 变量的 作用域 )和被 存储的
时间 ( 称为 变量的 存储期或生存期 )都是不同的。
按变量的 作用域来分类,变量可分为 局部 变量和 全局 变量;
按变量的 存储类别来分类, 动态存储方式与静态存储方式
所谓 动态存储方式,是指 在程序运行期间动态的分配存储
空间。 这类变量 存储在 动态存储空间(堆或栈) ;执行 其所在
函数或程序块 时开辟存储空间,函数或程序块 结束时释放 存储
空间 ;生命周期 为函数或程序块运行期间 。 主要有,函数的 形
参 和 函数 或程序块中定义的 局部变量 (未用 static声明)。
C++程序设计课件 设计制作:徐龙琴 48
所谓 静态存储方式, 是指 在程序运行期间分配固定的存储
空间。这类变量 存储在 全局数据区;当程序 运行时开辟 存储 空
间,程序 结束时释放存储空间 ; 生命周期 为程序运行期间。 主
要有,全局变量和用 static声明的静态变量。
代码区
全局数据区
堆区
栈区
?代码区:存放程序代码
?全局数据区:存放 全局 变量,静态
变量以及 常量, 变量 在程序运 行的
全程存在 。
?堆区,存放程序的动态数据,用于不能
预先确定变量存储空间的变量。当函数
malloc( )或 操作符 new为 变量分配空间 时,
生命期开始,当用 free( )或 delete释放该变
量的空间时,生命期结束。
?栈区:用于非 static类的 局部变量,
函数的 形式参数 以及 函数
调用时的有关信息 (如:函
数返回地址等)的内存分配
◇ 程序的内存区域 分为 以下四部分:
C++程序设计课件 设计制作:徐龙琴 49
全局变量, 在函数 外部定义的变量
在 编译时 就为其 分配内存
其 存放在全局数据区
默认 初始化为零
在整个程序 运行过程都存在
作用范围,从定义点起到本程序文件结束
局部变量,在 函数内部定义的 自动 auto变量
?运行到定义点时 在 内存的 栈区 为其分配内存 。 而在退出时被销毁。
?没有初始化
?作用范围,从 定义点起 到 本函数 或 本程序块结束
?形参 (也是局部变量):在函数调用时建立存储,并赋值以对应实参值
⒈ 按变量的作用域来分,全局 与 局部变量
C++程序设计课件 设计制作:徐龙琴 50
例,int xyz; // xyz全局 变量
void Foo (int xyz) // xyz 是 Foo函数中的局部变量
{ if (xyz > 0)
{
double xyz; // xyz是 if语句块中的局部变量
...
}
}
注意,用全局运算符,:,我们可以在局部作用域中访问到全
局变量。
例如,在上面 if语句中,我们增加一条语句,double t =,:xyz;
就可以把全局变量 xyz的值赋给局部变量 t。
C++程序设计课件 设计制作:徐龙琴 51
例:分析其运行结果
#include <stdoi.h>
int a=3,b;
int max(int a,int b )
{ int c;
c=a>b?a:b;
return ( c );
}
void main ( )
{ int a=8;
printf(“%d”,max(a,b));
}
/* a,b为全局变量 */
/* a,b为局部变量 */
/* a为局部变量 */
/* c为局部变量 */
运行结果为,8
C++程序设计课件 设计制作:徐龙琴 52
例:输入长方体的长 l,宽 w,高 h,求长方体体积及正, 侧, 顶
三个面的面积 。
#include <stdio.h>
int s1,s2,s3; //在 main()和 vs()中都可用
int vs(int a,int b,int c)
{ int v;
v=a*b*c; s1=a*b; s2=b*c; s3=a*c;
return v;
}
void main( )
{ int v,l,w,h;
printf("\ninput length,width and height,");
scanf("%d%d%d",&l,&w,&h);
v=vs(l,w,h);
printf("v=%d s1=%d s2=%d s3=%d\n",v,s1,s2,s3);
}
全局变量,在函数外部定义的变量
在内存的全局数据区分配
在编译时建立存储
默认初始化为零
在整个程序运行过程存在
作用范围:从定义点(说明点)
开始到本程序文件结束
局部变量,在函数内部定义的 auto变量
在内存的栈区分配
形参:在函数调用开始时建立存储,
并赋值以对应实参值
在函数内部定义的变量:运行到定义
点时建立存储,没有初始化
作用范围:从定义点(说明点)开始
到本函数或本程序块结束
C++程序设计课件 设计制作:徐龙琴 53
C++中每个 变量 和 函数有两个属性, 数据类型 和 存储类别 。
数据类型有,整型、字符型和实型等。 存储类别 指 的是数据在
内存中的存储方式。 存储方式 分为 两大类,动态 存储方式和 静
态 存储方式。具体的包含四种:自动的( auto)、寄存器的
( register)、静态的( static)和外部的( extern)。
1.动态存储方式,有两种,自动 类变量和 寄存器 类变量。
(1) 自动变量, 局部 变量 默认是自动变量 。自动变量用关键字
auto作为存储类别的声明,存储在 动态数据存
储区,其 生命周期 为函数或程序块执行期间,
作用域 也是其所在函数或程序块。
C++程序设计课件 设计制作:徐龙琴 54
例,
int fun( )
{ auto int a; // a为自动类变量
}
实际编程过程中,关键字,auto”可以省略 。
例如上述自动变量也可声明为下面形式:
int fun( )
{ int a;
}
自动变量, 属于 临时性存储,其 存储空间 可以被若干变
量 多次覆盖 使用。 自动变量每次调用都重新
初始 化,
C++程序设计课件 设计制作:徐龙琴 55
例, 寄存器变量的使用 。
#include <iostream.h>
void main( )
{ register int i;
int sum=0;
for(i=1;i<=100;i++)
sum+=i;cout<<"1+2+...+100="<<sum<<endl; }
⑵ 寄存器变量,用 register作为存储类别 的声明。寄存器变量 存储
在 CPU的 通用寄存器 中,这样将减少 CPU从内存
读取数据的时间,能提高程序运行效率 。寄存器
变量的 生命周期 和 作用域 为其定义所在的函数或
程序块 。一般情况下,将局部 最常用到的变量声
明为寄存器变量
程序运行结果如下:
1+2+...+100=5050
C++程序设计课件 设计制作:徐龙琴 56
1)寄存器变量 不宜定义过多 。因寄存器数量是有限的。如果寄
存器变量过多或通用寄存器被其他数据使用,系统将自动
把
寄存器变量转换成自动变量。
2)寄存器 变量 的数据 长度 与 通用寄存器的长度相当 。
3) 寄存器变量 只能是 char,int或 指针型。
2.静态存储方式, 使用静态存储方式的变量有两种:
外部变量 和 静态变量 。
寄存器变量的使用应注意以下问题:
C++程序设计课件 设计制作:徐龙琴 57
外部变量,就是 没有被声明为静态的全局变量,存储在 全局
数据区,生命周期 为程序执行期间。
外部变量
声明用 extern实现。如果 在全局变
量定义点之前
的函数 要引用该全局变量 或 另 一
个源文件中的函
数 要引用 该全局变量,需要在函数
内对 要引用的
全局变量加 extern说明
例:
void main( )
{ extern A,B; /*外部变量声明 */
printf(“%d”,( A>B?A:B));
}
int A=13,B= -8 /*外部变量定义 */
C++程序设计课件 设计制作:徐龙琴 58
静态变量, 变量定义前加上 static关键字,就定义了静态变量。 静态变
量 在编译就为其分配空间和赋初值,静态变量 与 全局变量
具有相同 的 存储期 。 静态的全局变量 只能在其
定义 的文件有
效,静态的局部变量 只能在定义该局部变量
的局部作 用域中
有效。 静态变量的值具有继承性且其默认的
初值为 0。
例:
static int x; // 静态全局变量
void Error (char a)
{
static int c= 0; // 静态局部变量
...
}
C++程序设计课件 设计制作:徐龙琴 59
# include <stdio.h>
void main ( )
{ void inc1( ),inc2( );
inc1( ); inc1( ); inc1( );
inc2( ); inc2( ); inc2( );
}
void inc1( )
{ int x = 0;
x++;
printf ("in inc1 x=%d\n",x);
}
void inc2( )
{ static int x=0;
x++;
printf ("in inc2 x=%d\n",x);
}
例, 分析下列程序的运行结果。
运行结果,
in inc1 x= 1
in inc1 x= 1
in inc1 x= 1
in inc2 x= 1
in inc2 x= 2
in inc2 x= 3
C++程序设计课件 设计制作:徐龙琴 60
#include <stdio.h>
void main( )
{ auto int x = 1;
void f1(void),f2(int);
f1( ); f2(x);
printf (" \n x=%d",x);
}
void f1 ( void )
{ int x = 3;
printf ("x=%d\t",x);
}
}
void f2 (int x)
{ printf (“x=%d\t”,++x);
运行结果:
x=3 x=2
x=1
例, 分析下列程序的运行结果。
C++程序设计课件 设计制作:徐龙琴 61
§ 程序举例
例 1,计算如下公式,并输出结果:
?
?
?
?
?
?
??
?
22
2222
r)*(
2
1
r)()(
ssrS I N
ssS I NrS I N
k
当
当
其中 r,s的值由键盘输入。 sin x的近似值按如下公
式计算,计算精度为 10-6
??
?
?
???????? 0
12753
)!12()1(!7!5!3!1 n
n
n
n
xxxxxS I Nx ?
C++程序设计课件 设计制作:徐龙琴 62
??
?
?
???????? 0
12753
)!12()1(!7!5!3!1 n
n
n
n
xxxxxS I Nx ?
算法分析:
要求 K的值 关健是 如何利用给的公式 求 sinx的值,分析公式:
得:
第 一 项,t1=x/1!
第 二 项,t2=- x3/3!=-t1*x2/(2 *3);
第 三 项,t3=x5/5!=-t2*x2/(4 *5);
……
第 N项,tn=x2n+1/(2n+1)!=-tn-1*x2/((2n-1)(2n- 2));
将其
+
直到 tn<10-6
其和,sum = sinx
C++程序设计课件 设计制作:徐龙琴 63
double tsin(double x)
{
double sum=0,t=x;
int n=1;
do {
sum=sum+t;
n++;
t=-t*x*x/(2*n-1)/(2*n-2);
}while(fabs(t)>=1e-6);
return sum;
}
求 sinx的值的函数 tsin() 为:
C++程序设计课件 设计制作:徐龙琴 64
#include <iostream.h>
#include<math.h>
void main ( )
{double k,r,s;
double tsin(double x);
cout<<"r=";
cin>>r;
cout<<"s=";
cin>>s;
if (r*r<=s*s)
k=sqrt(tsin(r)*tsin(r)+tsin(s)*tsin(s)) ;
else
k=tsin(r*s)/2;
cout<<k<<endl;
}
求 K完整的程序为, double tsin(double x)
{double sum=0,t=x;
int n=1;
do {
sum=sum+t;
n++;
t=-t*x*x/(2*n-1)/(2*n-2);
}while(fabs(t)>=1e-6);
return sum;}
C++程序设计课件 设计制作:徐龙琴 65
例 2,有缺省参数的函数
#include <iostream.h>
#include <iomanip.h>
void f(int i=5,long j=40034,float x=10.25,char ch='Z',double d=4.3234);
void main()
{ f(); // 使用所有的缺省参数
f(2); // 覆盖第一个缺省参数
f(2,75037); // 覆盖第一和第二个缺省参数
f(2,75037,35.88); // 覆盖第一、第二和第三个缺省参数
f(2,75037,35.88,'G'); //覆盖第一、第二、第三和第四个缺省参数
f(2,75037,35.88,'G',.0023); // 未使用缺省参数
}
void f(int i,long j,float x,char ch,double d)
{ cout << setprecision(4) << "i," << i << " " << "j," << j;
cout << " x," << x << " " << "ch," << ch;
cout << " d," << d << "\n";
return; }
该程序的运行结果如下:
i,5 j,40034 x,10.25 ch,Z d,4.3234
i,2 j,40034 x,10.25 ch,Z d,4.3234
i,2 j,75037 x,10.25 ch,Z d,4.3234
i,2 j,75037 x,35.88 ch,Z d,4.3234
i,2 j,75037 x,35.88 ch,G d,4.3234
i,2 j,75037 x,35.88 ch,G d,0.0023
C++程序设计课件 设计制作:徐龙琴 66
例,函数中变量和程序块中变量同名。
#include <iostream.h>
void main( )
{ int a=1,b=2,c=3;
cout<<a<<","<<b<<","<<c<<endl;
{ int b=4;
cout<<a<<","<<b<<","<<c<<endl;
a=b;
{ int c;
c=b;
cout<<a<<","<<b<<","<<c<<endl; }
cout<<a<<","<<b<<","<<c<<endl;
}
cout<<a<<","<<b<<","<<c<<endl;
}
程序运行结果如下:
1,2,3
1,4,3
4,4,4
4,4,3
4,2,3
C++程序设计课件 设计制作:徐龙琴 67
例,函数重载
#include <iostream.h>
#include <iomanip.h>
int abs(int i);
float abs(float x);
void main()
{int ians; // 保存返回值
float fans;
int i = -15;
float x = -64.53;
ians = abs(i);
cout <<,整数 -15的绝对值是, << ians <<,\n”;
fans = abs(x);
cout <<,单精度浮点 -64.53的绝对值是, <<fans ;
}
int abs(int i)
{ if (i < 0) return i *( -1);
else return i; }
float abs(float x)
{ if (x < 0.0) return x * (-1.0);
else return x; }
运行该程序,输出结果如下:
整数 -15的绝对值是 15
单精度浮点 -64.53的绝对值是 64.53
C++程序设计课件 设计制作:徐龙琴 68
例,汉诺塔问题,
汉诺塔问题只能用递归方法解决
婆罗门庙里有一个塔台,台上有 3根标号为 A、
B,C的用钻石做成的柱子,在 A柱上放着 64
个金盘,每一个都比下面的小一点。把 A柱
上的金盘全部移到 C柱上的那一天就是世界
末日。移动的条件是:一次只能移动一个金
盘,移动过程中大的金盘不能放在小金盘上。
庙里的僧人一直移个不停。因为全部的移动
是 264- 1 次,如果每秒移动一次的话,需要
500亿年。 编写一个程序,输入 A柱上的盘子
数量,输出正确的移动步骤。
C++程序设计课件 设计制作:徐龙琴 69
A B C
C++程序设计课件 设计制作:徐龙琴 70
A B C
1、把前 2个盘借助 C,从 A移到 B
2、把 3号盘从 A移到 C
3、把前 2个盘借助 A,从 B移到 C
1、第一个盘移到 C
2、第二个盘移到 B
3、第一个盘移到 B
1、第一个盘移到 A
2、第二个盘移到 C
3、第一个盘移到 C
C++程序设计课件 设计制作:徐龙琴 71
分析,将 n 个盘子从 A移到 C可以分解为下面 三个步骤:
① 将 A 上 n-1个盘子移到 B上(借助 C) ;
② 把 A上剩下的一个盘子移到 C上 ;
③ 将 n-1个盘子从 B移到 C上(借助 A) ;
事实上,上面三个步骤包含两种操作:
①将多个盘子从一个柱移到另一个柱上,这是一个递归的过程。
Hanoi函数实现。
②将 1个盘子从一个柱上移到另一柱上。用 move函数实现。
将上面三个步骤用语句表达:
Hanoi(n-1,a,c,b);
Move(a,c);
Hanoi(n-1,b,a,c);
C++程序设计课件 设计制作:徐龙琴 72
汉诺塔的递归解:
#include <iostream.h>
void move(char cha,char chc);
void hanoi(int n,char cha,char chb,char chc);
void main()
{ int m;
cout<<"Enter the number of diskes:";
cin>>m;
cout<<"the steps to moving "
<<m<<" diskes:"<<endl;
hanoi(m,'A','B','C');
}
void hanoi(int n,char cha,char chb,char chc)
{ if (n==1) move (cha,chc);
else { hanoi (n-1,cha,chc,chb);
move(cha,chc);
hanoi(n-1,chb,cha,chc);}
}
void move(char cha,char chc)
{ cout<< cha <<"-->"<<chc
<<endl;
}
运行结果:
Enter the number of diskes,3
the steps to moving 3 diskes:
A-->C
A-->B
C-->B
A-->C
B-->A
B-->C
A-->C