一、课时内容
函数定义
函数要先定义后使用(调用)。
函数的一般是形式为:
类型标识符 函数名(形参表)
{
函数体 //执行语句
}
关于函数的定义有以下说明:
·函数的数据类型是函数的返回值类型(若数据类型为void,则无返回值)。
·函数名是标识符,一个程序中除了主函数名必须为main外,其余函数的名字按照标识符的取名规则可以任意选取。
·形参表可以是空的(无参函数)也可以有多个形参,用逗号隔开,不管有无参数,函数名后的圆括号都必须有。形参可以是变量名、数组名或指针名,作用是实现主调函数与被调函数之间的关系。
·函数中最外层一对花括号{}括起来的若干个说明语句和执行语句组成各一个函数的函数体。函数的功能由函数体内的语句决定。
·函数不允许嵌套定义,但是允许嵌套使用。
函数在没有被调用的时候是静止的,此时的形参只是一个符号,它标志着在形参出现的位置应该有一个什么类型的数据。函数被调用时才执行。
函数定义的例子:
定义一个函数,返回两个数中的较大数
int max(int x,int y)
{
return x>y? x:y;
}
函数的声明和调用
函数的声明
调用函数之前先要声明函数原型。在驻地凹函数中或所有函数定义之前按如下形式声明:
类型说明符 被调函数名(含类型说明的形参表)
如果是在所有函数定义之前声明了函数原型,那么该函数在本程序文件中任何地方都有效。
如果是在某个主调函数内部声明了被调用函数的原型,那么该原型就只能在这个函数内部有效。
函数的调用
声明了函数原型之后,便可以按如下形式调用函数:
函数名(实参列表)
实参列表中应给出与函数原型形参个数相同、类型相符的实参。在主调函数中的参数成为实参,实参一般应具有确定的值。实参可以是变量、表达式,也可以是已有确定值的变量、数组或指针名。
函数的返回值
在组成函数体的各类语句中,值得注意的是返回语句return。它的一般形式是:
return(表达式);
其功能是把程序流程从被调函数转向主调函数并把表达式的值带回主调函数,实现函数的返回。
在圆括号表达式的值实际上就是该函数的返回值。其返回值的类型即为它所在函数的函数类型。
函数的传值调用
传值调用
这种调用方式是将实参的数据值传递给形参,即将实参值拷贝一个副本存放在被调用函数的栈区中。在被调用函数中,形参值可以改变,但不影响主调函数的实参值,参数传递方向只是从实参到形参,简称单项值传递,例:
#include<iostream>
using namespace std;
void swap(int a,int b)
{
int tmp=a;a=b;b=tmp;
}
int main()
{
int c=1,d=2;
swap(c,d);
cout<<c<<d<<endl;
return 0;
} //程序输出为:1 2
传址调用
这种调用方式是将实参变量的地址值传递给形参,这时形参值是指针,即让形参的指针指向实参地址,这里不再是将实参拷贝一个副本给形参,而是让形参直接指向实参,这就提供了一种可以改变实参变量的值的方法,现在用传址调用来实现swap:
#include<iostream>
using namespace std;
void swap(int &a,int &b)
{
int tmp=a;a=b;b=tmp;
}
int main()
{
int c=1,d=2;
swap(c,d);
cout<<c<<d<<endl;
return 0;
} //程序输出为:2 1
全程变量、局部变量及它们的作用域
在函数外部定义的变量成为外部变量或全局变量,在函数内部定义的变量成为内部变量或局部变量。
全局变量
定义在函数外部没有被花括号括起来的变量称为全局变量,全局变量的作用域是从变量定义的位置开始到文件结束,由于全局变量是在函数外部定义的,因此对所有函数而言都是外部的,可以在文件中位于全局变量定以后面的任何函数中使用。
例:输入两个正整数,编程计算两个数的最小公倍数。
程序如下
#include<iostream>
using namespace std;
int x,y;
int gcd(int x,int y)
{
int r=x%y;
while(r!=0)
{
x=y;
y=r;
r=x%y;
}
return y;
}
int lcm()
{
return x*y/gcd(x,y);
}
int main()
{
cin>>x>>y;
cout<<lcm()<<endl;
return 0;
}
使用全局变量的说明
·在一个函数内部,即可以使用本函数定义的局部变量,也可以使用在此函数前定义的全局变量。
·全局变量的作用是使得函数间多了一种传递信息的方式。
·过多的使用全局变量,会增加调试难度。
·过多的使用全局变量,会降低程序的通用性。
·全局变量在程序执行的全过程中一直占用内存单元。
·全局变量在定义是若没有赋初值,其默认值为0。
局部变量
·局部变量的作用域实在定义该变量的函数内部。
·由于局部变量的作用域仅局限于本函数内部,所以,在不同的函数中变量名可以相同,它们分别代表不同的对象,在内存中占据不同的内存单元,互不干扰。
·一个局部变量和一个全局变量是可以重名的,在相同的作用域内局部变量有效时全局变量无效,即局部变量可以屏蔽全局变量。
·在代码块中定义的变量的存在时间和作用域将被限制在该代码块中。
·主函数main中定义的变量也是局部变量,这一点与其他程序设计语言不同。
·全局变量数组初始全部为0,局部变量值是随机的,要初始化初值,局部变量受栈空间大小限制,大数组需要注意。
递归算法
递归概念
当函数的定义中,其内部操作又直接或间接的出现对自身的调用,则称这样的程序嵌套定义为递归定义。
递归通常把一个大型复杂的问题层层转化为一个与原问题形似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。
递归程序在执行过程中,一般具有如下模式;
1 将调用程序的返回地址、相应的调用前的变量都保存在系统堆栈中;
2 执行被调用的函数;
3 若满足退出递归调用,则退出递归,并从栈顶上弹回返回地址、取回保存起来的变量值,继续沿着返回地址,向下执行程序;
4 否则继续递归调用,只是递归调用的参数发生变化;增加一个量或减少一个量,重复执行直到递归调用结束。
能够用递归算法解决的问题,一般满足如下要求:
1 需要求解的问题可以化为子问题求解,其子问题的求解方法与原问题相同,只是规模上的增加或减少;
2 递归调用的次数是有限的,必须有递归结束的条件(成为递归边界)
二、常见题型
1.输入1个整数n。从小到大依次输出n的所有因子。
20样例输出
2 4 5 10 4
程序如下:
#include<bits/stdc++.h>
using namespace std;
int yinzi(int x,int y);
int main()
{
long long n,i,s=0;
cin>>n;
for(i=2;i<=n/2;i++)
if(yinzi(n,i))
{
s++;
cout<<i<<" ";
}
cout<<s;
return 0;
}
int yinzi(int x,int y)
{
if(x%y==0)
return 1;
else
return 0;
}
2.
验证“歌德巴赫猜想”,即:任意一个大于2的偶数均可表示成两个素数之和。输入输入只有一个正整数x。(x是偶数,x <= 2000 且 x > 2)输出输出这个数的所有分解形式,形式为:
x = y + z
其中x为待验证的数,y和z满足y + z = x,而且 y <= z,y和z均是素数。
如果存在多组分解形式,则按照y的升序输出所有的分解,每行一个分解表达式。
注意数和符号之间隔一个空格。样例输入
输入样例1: 10 输入样例2: 100
程序如下:
#include<bits/stdc++.h>
using namespace std;
int sushu(int n);
int main()
{
int x,j;
cin>>x;
for(j=2;j<=x/2;j++)
{
if(sushu(j))
if(sushu(x-j))
{
cout<<x<<" "<<"="<<" "<<j<<" "<<"+"<<" "<<(x-j);
cout<<endl;
}
}
return 0;
}
int sushu(int n)
{
int i,t=1;
for(i=2;i<=sqrt(n);i++)
if(n%i==0)t=0;
if(t==1)
return 1;
else
return 0;
}
3
求从1加到n的阶乘的和,输入n的值,按要求输出。
5样例输出
153
程序如下:
#include<bits/stdc++.h>
using namespace std;
int jiecheng(int n);
int main()
{
int x,sum=0;
int j;
cin>>x;
for(j=1;j<=x;j++)
sum+=jiecheng(j);
cout<<sum;
return 0;
}
int jiecheng(int n)
{
int s=1;
int i;
for(i=1;i<=n;i++)
s=s*i;
return s;
}
三、学习心得
通过对于函数的学习,理解了C++如何构建一个具备特殊功能的函数来达到自己的目的,使主函数变得更加简单。也提高了对本门课程的兴趣,对于今后的学习劲头更足。