3.4 循环的中断
3.4.1 break 语句例:
#include <iostream.h>
#include <conio.h>
int main()
{
while(1) {
cout << "This loop will ran forever,until you hit a key\n";
if(kbhit())
break;
}
cout << "\nLoop is over.\n";
return 0;
}
程序中的 kbhit() 是 C++
语言的一个标准函数。
3.4.2 continue 语句
#include <iostream.h>
#include <stdlib.h>
int main()
{
for(int i = 0; i < 100; i ++) {
int n;
n = rand() % 100;
if(n % 2)
continue;
cout << n << endl;
}
return 0;
}
说明:
1,程序中的 rand() 是 C++
语言的一个标准函数,其作用是产生一个 0~MAXINT
的随机整数。
2,if 语句中的 n % 2 等效于
n % 2 != 0。
3,该程序输出不超过 100 个随机偶数。
3.4.3 exit() 和 abort() 函数这两个函数都是 C++ 语言的标准函数。其作用都是终止整个程序的运行。 exit() 在终止程序前还会做一些善后工作。
为了能在程序中使用这两个函数,必须在调用它们之前加上一条预处理指令:
#include <stdlib.h>
应当说明的是,exit() 函数是带有一个整型参数的函数,
调用它时必须在其括号中放置一个整数值,而 abort() 函数则无参数。例:
if(divider == 0) if(divider == 0)
exit(1); abort();
//… //…
3.5 goto 语句与标号
goto label;
//…
label:
//…
其中,label 是一个标号,它可以是任何一个合法的 C++ 标识符。
由于 goto 语句会破坏程序的逻辑结构,现代程序设计中应避免使用该语句。
第 4章 函数
4.1 函数
4.1.1 定义函数
type func_name(<arg_list>)
{
func_body
}
其中,func_name 是 函数名,它可以是任何一个合法的标识符; arg_list 叫做 形式参数表,外界传递给函数的数据将在这里一一列出; func_body 为 函数体,它由一系列 C++ 语句构成以完成某些有意义的操作。 type 是函数的 返回值 (也叫函数值)的类型,它可以是任何一个已存在的数据类型。
例:定义一个阶乘函数。
#include <iostream.h>
void Facto()
{
int n;
long fac = 1;
cout << "Enter a integer,";
cin >> n;
for(int i = 1; i <= n; i ++)
fac *= i;
cout << "The factorial of " << n << "is " << fac << endl;
}
4.1.2 函数的调用
<var => func_name(<params>)
其中,params 是一个个与函数各参数数据类型相匹配的表达式,叫做函数的 实际参数 。而 var 是一个与函数值类型相匹配的变量,它被用来接受函数的返回值。
例:
Facto();
就是对前边所定义的阶乘函数的调用。
4.2 函数间的数据传递
4.2.1 函数的参数和返回值
4.2.1.1 函数的参数一个函数可以有零个或多个参数,例如:
f(int x,int y,char c)
{
//…
}
注意:每个参数的类型必须单独给出。
f(int x,y,char c) // 错误!
4.2.1.2 函数的返回值一个函数可以有零个或一个返回值,若函数无返回值,则必须将它的类型定义成 void。
无返回值的函数就相当于 Pascal 语言中的过程或 BASIC 语言中的子程序。
4.2.1.3 return 语句
return <expression>;
return 语句有两个作用,第一是终止函数的运行,返回到调用它的那个函数(叫做 主调函数 或 调主 )中;第二是不仅终止函数的运行,同时还向调主返回一个值。
例,阶乘函数的另一个版本
#include <iostream.h>
unsigned long Facto(int n)
{
unsigned long fac = 1;
for(; n > 0; --n)
fac *= n;
return fac;
}
// 阶乘函数的定义
void main()
{
unsigned long lResult;
for(int i = 5; i < 50; i += 5) {
lResult = Facto(i);
cout << lResult << endl;
}
}
对于本例,main() 函数改写成如下形式将显得更简练:
void main()
{
for(int i = 5; i < 50; i += 5)
cout << Facto(i) << endl;
}
4.2.2 函数原型
type func_name(<arg_list>);
函数原型 ( Function prototype) 是对函数的 引用性 说明。
例如:
unsigned long facto(int n);
void main()
{
for(int i = 5; i < 50; i += 5)
cout << facto(i) << endl;
}
在此情况下,函数 facto()
的定义就可以写在 main()
函数的后边,甚至可以写在另一个文件中。
4.2.3 函数的值调用函数的值调用也叫做函数的赋值调用、传值调用,是函数实参与形参结合的一种方式。其本质是:实际参数将其值赋给形式参数。因此,函数对形参的任何修改都不会对实参产生影响。
当函数的参数为普通变量形式时,其参数的结合方式就属于值调用。
#include <iostream.h>
void main()
{
void Swap(int x,int y);
int a = 3,b = 5;
Swap(a,b);
cout << "a = " << a << '\t' << "b = " << b << endl;
}
void Swap(int x,int y)
{
int t = x;
x = y;
y = t;
}
输出为,3 5
4.3 C++ 的库函数所谓库函数就是前面所说的标准函数,他们是 C++ 语言软件包预定义的函数。应当说明的是:不同的具体实现所提供的库函数不尽相同,但均提供了 ISO 标准中规定了的库函数。
库函数的函数原型分别在不同的头文件中说明。因此,程序在调用某个库函数前必须利用 include 预处理指令嵌入相应的头文件。例如,若程序中需要调用 sqrt() 函数,由于该函数的原型在头文件 math.h 中说明,所以在调用该函数之前,程序中必须存在以下的预处理指令:
#include <math.h>
由于不同编译器所提供的头文件的文件名不尽相同,使用时一定要参阅具体编译器的相应资料。
4.4 作用域和存储类
4.4.1 作用域作用域体现了标识符的可见性。一个标识符的作用域是程序中的一个区域,在作用域中这个标识符是可访问的。
C++ 语言的作用域共有 5 种:块作用域、文件作用域、函数原型作用域、函数作用域和类作用域。
其中,函数作用域仅与 goto 语句有关,本课程不做介绍;类作用域将在第 8 章介绍。
4.4.1.1 块作用域块是程序中一块用花括号括起来的区域。在块中说明的标识符具有块作用域,在块中说明的变量叫做 局部变量 。
例:
void f()
{
int j = 3;
{
int i;
i = j; // 正确
}
cout << i << endl; // 错误
}
4.4.1.2 文件作用域在所有块之外说明的标识符具有文件作用域,具有文件作用域的变量叫做 全局变量 。
应当说明的是:在一个块中,局部变量将屏蔽同名的全局变量,
但允许利用作用域运算符,::”来访问同名的全局变量。
例:
int i;
void f()
{
int i = 3;
:,i = 5;
cout << i << '\t' <<,,i << endl;
}
4.4.1.3 函数原型作用域在函数原型的形参表中说明的标识符具有函数原型作用域。这就是说,函数原型的中的形式参数名仅仅在函数原型的那对圆括号中为可见的。所以参数名在函数原型中可以与函数定义中不相同。
例:
int f(int a,int b); // 函数原型
int f(int x,int y) // 函数定义
{
//…
}
有时,甚至在函数原型中省略参数名:
int f(int,int);
4.4.2 存储类标识符的作用域限定了标识符的可见性,而标识符(主要指变量)的存储类则指定了标识符的生存期。变量的存储类还影响
C++ 编译器为变量分配内存的策略。
一个程序只有被调入内存后才可以运行。程序所占有的内存被分为 3 个部分:代码区、静态存储区(通常称其为 堆,Heap)
和动态存储区(通常称其为 栈,Stack)。
在 C++ 语言中,共有 4 种存储类:自动的、静态的、寄存器的和外部的。
4.4.2.1 自动变量用关键字 auto 修饰的变量为自动变量。 C++ 允许省略 auto
关键字,所以该关键字几乎从不使用。
自动全局变量存放在静态区,自动局部变量存放在动态区。
4.4.2.2 静态变量用关键字 static 修饰的变量为静态变量,静态变量都被存放在静态区。
将全局变量说明成静态的,其目的是为了阻止书写在其他文件中的代码访问该变量。将局部变量说明成静态的,则是为了在程序运行出了该变量的作用域后仍能保留变量的值。
例:
int i; // 自动变量
static int j; // 静态变量例:使用静态变量
int Func(int); int Func(int n)
{
void main() static int s = 0;
{
for(int i = 0; i < 10; i ++) s ++;
Func(0); if(n == 0)
cout << Func(1) << endl; return 0;
} else
return s;
}
4.4.2.3 寄存器变量用关键字 register 修饰的变量为寄存器变量。将变量说明成寄存器的是 请求 编译器将该变量存放在 CPU 的寄存器中。至于该变量最终是否被存在 CPU 的寄存器中,则取决于当时
CPU 是否有空闲寄存器。另外,C++ 编译器的优化功能会尽量将那些使用频率比较高的变量(主要是循环变量)优化到寄存器中,所以,该关键字近来很少使用。
4.4.2.4 外部变量用关键字 extern 修饰的全局变量为外部变量。外部变量说明属于引用性说明,它指出该全局变量已经在另一个文件中定义过了,本文件中的代码将要使用该变量。
// FUNC1.CPP
extern int n; // 引用性说明
void Func1(int d)
{
n /= d;
}
// FUNC2.CPP
extern int n; // 引用性说明
void Func2(int m)
{
n *= m;
}
// MAIN.C
#include <iostream.h>
int n = 30; // 定义性说明
void main()
{
void Func1(int); // 函数原型
void Func2(int);
Func1(3);
cout << n << endl; // 输出 10
Func2(5);
cout << n << endl; // 输出 50
}
4.5 函数的递归调用所谓递归调用( Recursion)是指一个函数直接或间接地调用其自身。
现实生活中存在着许多递归定义的事务,利用递归函数可以很方便地对这样的事务进行编码。
例:递归的阶乘函数
unsigned long Facto(int n)
{
if(n == 0)
return 1;
return(n * facto(n - 1));
}
数学定义:

0)!1(
01
!
nnn
n
n
递归函数中必须有终止机制 (如例中的
if 语句 ),否则将是一个无限递归。
现在以函数调用
n = Facto(3);
来说明递归函数的执行过程
return
3*
Facto(2)
return
2*
Facto(1)
return
1*
Facto(0)
return
1
3 2 1 0
11*12*13*2n
4.6 内联函数函数调用时的时间和空间开销常常是比较大的:
1,保护断点 将主调函数中的下一条指令入栈;
2,保护现场 将一些重要寄存器中的内容入栈;
3,参数入栈 ;
4,执行函数体;
5,保存返回值 ;
6,恢复现场 寄存器中的内容出栈;
7,恢复断点 主调函数中的下一条指令出栈;
内联函数是由关键字 inline 修饰的函数,它是一种提高程序设计和执行效率的解决方案。
无论是否使用了函数原型,内联函数的定义必须出现在对函数的调用之前 。
#include <iostream.h>
inline int Max(int a,int b)
{
return (a > b? a,b);
}
void main()
{
int x,y;
cin >> x >> y;
cout << Max(x,y) << endl;
}
当该程序被编译成功后,程序将不存在语句:
cout << Max(x,y) << endl;
该语句将以如下的形式出现:
cout << (x >= y? x,y) << endl;
注意:关键字 inline 是 请求 编译器将其所修饰的函数处理成内联的。
4.7 带有缺省参数的函数
C++ 语言允许函数的参数带有缺省值。对于这样的函数,调用时若给出了实参的值,函数将使用该给定值;否则将使用其缺省值。
#include <iostream.h>
#include <math.h>
void Delay(int n = 100);
void main()
{
Delay(500); // 延时 500 个单位
Delay(); // 延时 100 个单位
Delay(sqrt(100)); // 延时 10 个单位
}
void Delay(int n)
{
for(; n > 0; n --);
}
说明:
1,缺省参数的说明必须出现在函数调用之前;
2,若函数拥有多个参数,则缺省参数必须自右至左地连续定义。例如:
正确的说明
int f(int a,float b = 0.5,char c = ' ',int d = 10);
错误的说明
int f(int a = 10,float b = 0.5,char c = ' ',int d);
int f(int a,float b = 0.5,char c = ' ',int d = 10);
4.9 函数重载重载 ( Overloading)是实现多态性的一种手段。 C++ 语言中的重载包括函数重载和运算符重载。
从技术上讲,函数重载就是同一个函数名对应多个函数。
例:
int Abs(int a)
{
return (a >= 0? a,-a);
}
float Abs(float a)
{
return (a >= 0? a,-a);
}
C++ 对函数重载的唯一要求就 是:各重载函数在参数的个数或类型上必须有所区别。例如:
正确的函数重载
int func(int);
char func(int,int);
int func(char);
int func(int,char);
float func(char,int);
错误的函数重载
int func(int);
char func(int);
float func(int);
习题:
4,5,6,7