returna+b;
}
2、运行结果
3、程序分析
1)程序输出的五段内容分别是从函数func和主函数中输出的。
第一段和第三段从函数func中输出,第二段和第四段从主函数中输出。
2)在函数main和函数func中各自定义了局部变量a和b,它们的作用域在各自的函数范围之内,因此在两个函数中输出的a,b值是不相干的。
主函数中的a值开始为5,后来增1后变成6;主函数中的b值从函数func的返回值而来,而函数func返回的值是它的局部变量a和b的和,所以第二段和第四段中的b值分别为第一段和第三段中的a+b的值。
函数func中的局部变量a是一个临时变量,每次进入函数时都重新赋值为,然后被自增1,所以每次输出都是2;变量b是一个局部静态变量,所以在退出函数func时它能够保持原来的值,在第一次调用func时,b的初值为10,然后自增1,所以值为11,第二次调用func时,b的值保持为11,所以再次自增后,b值成为12。
3)n是一个全局变量,因此它的值可以在全局范围内被访问和修改‘在函数func中对n的修改可以反映到主函数中,这样在主函数中两次输出的n值分别为1和2。
4)函数func的参数x的初值由调用它的实在参数赋给,因此初值分别为5和6,在该函数中对x做了自增操作,所以输出的值分别为6和7。
5)函数func的参数有一个缺省值为10,所以在最后一次调用该函数时,X值变成10,在函数中增1后,X值变成11。
6)函数调用中发生数的传递是单向的,只能把实参的值传递给形参,而不能把实参的值反向传给形参,因此在函数调用中形参的值改变不会改变实参的值;函数中的形参和调用时的实参都是数组名时,传递方式为地址传递,此时形参和实参共用同一段内存;都是变量时,传递方式为值传递,而且实参与形参互不影响。
4、改变main()函数中a的值令a=10,改变func()函数中b的值令staticintb=10;程序运行结果如下:
5、思考与扩展
1)将函数func()中的变量staticintb=10;改为intb,此时b没有初始化,因此b的值就是地址值;程序运行结果:
2)如果将main()函数中定义变量的语句inta,b;移到程序第三行,程序运行结果是没有变化的,因为此时a,b为全局变量,在整个程序中都起作用,由于函数结构没有改变,因此结果是没有变化的。
题目2函数的递归调用和多文件结构
利用非递归方式实现
1、程序源代码
#include
usingnamespacestd;
doublefn(intn);//声明函数nn求n!
doubleCnr(intn,intr);//声明函数Cnr求C(n,r)
intmain()
{
intn,r;
while
(1)
{
cout<<"pleaseinputn&&r(输入00结束):
"<cin>>n>>r;//输入00表示结束程序
if(n==0&&r==0)
break;
if(n<1||ncout<<"输入无效!
"<else
cout<}
return0;
}
doublefn(intn)//定义函数nn求n!
{
doublesum=1;
for(inti=1;i<=n;i++)
sum=sum*i;
returnsum;
}
doubleCnr(intn,intr)//定义函数Cnr求C(n,r)
{
doubles1,s2,s3;
s1=fn(n);
s2=fn(r);
s3=fn(n-r);
returns1/(s2*s3);//Cnr的计算公式
}
2、运行结果
3、程序调试
(1)、定义求C(n,r)函数时,不能定义为C(intn)因为C是关键词,编译时会通不过,因此在定义函数时我避开了关键词。
(2)、定义两个double型函数时注意return的返回值:
如果都习惯了return0那么结果都是0,因此在执行return函数时注意要return的对象。
利用递归方式实现
1、程序代码
#include
usingnamespacestd;
doubleCnr(intn,intr);//声明递归函数
intmain()
{
intn,r;
while
(1)
{
cout<<"Pleaseinputn&&r:
"<cin>>n>>r;
if(n==0&&r==0)//输入00表示结束程序
break;
if(n<1||ncout<<"Inputinvalid!
"<else
cout<}
return0;
}
doubleCnr(intn,intr)//定义求C(n,r)
{
if(r==0)//判断是否满足递归结束条件
return1;
if(r==1)
returnn;
returnCnr(n,r-1)*(n-r+1)/r;//递归规律注意(/n和/r)
}
2、运行结果
3、程序调试
在最后归纳递归函数的时候,如果把
这一句换成
那么结果就会出现结果不对的情况:
原因就是递归错误!
4、思考与扩展
1、写递归函数需考虑的要素:
a.怎样取一个变量或多个往下递归(不是绝对,但是推荐这么做,变量在传递中要有变化)。
b.怎样终止递归,要设置一个合理的终止条件(原来的规律不能成立,函数体递归前的代码不再能重复)。
c.递归过程中的暂时或中间结果怎样保存(不是每一个递归都需考虑这个情况)。
2、在递归版本中,当n大到26万时系统将发生栈溢出报错;我个人觉得在递归与非递归之间觉得非递归函数比较好,因为它节省了存储空间,大大提高了程序的执行效率。
3、多文件结构中头文件的作用是:
避免调用函数时发生小错误;而将程序划分多个程序好处是:
1)、避免一而再,再而三地重复编译函数,因为编译器总是以文件为单位工作的。
如果一个文件中包含的函数太多,则由于被修改的函数总是少数的几个,所以大多数正确的函数都得重新编译一次;2)、使程序更加容易管理。
可以将程序按逻辑功能划分,分解成各个源文件,便于程序员的任务安排,以及程序调试;3)、把相关函数放到一特定源文件中。
题目3条件编译
1、第一种条件编译
1)程序源代码
#include
usingnamespacestd;
#defineyellow//定义一个标志符
intmain()
{
charch;
cout<<"请输入一个字母:
"<cin>>ch;
while(ch<65||ch>90&&ch<97||ch>122)
{
cout<<"输入的不是字母,重新输入:
"<cin>>ch;
}
#ifdefyellow//标志符存在时执行此段代码,否则执行else后的代码段
if(ch>=65&&ch<=90)
ch+=32;
cout<<"转换成小写字母为:
"<#else
if(ch>=97&&ch<=122)
ch-=32;
cout<<"转换成大写字母为:
"<#endif
return0;
}
2)、运行结果
标志符存在时结果为:
注析标志符时结果为:
与计划结果一致!
3)、程序调试
刚开始编译代码时没有定义标志符,导致后面的程序执行停止,没有达到条件编译的效果;在加上#defineyellow和#ifdefyellow后,此时就实现了条件编译的功能!
2、第二种条件编译
1)、程序代码
#include
usingnamespacestd;
#defineLETTER1
intmain()
{
charch;
cout<<"请输入一个字母:
"<cin>>ch;
while(ch<65||ch>90&&ch<97||ch>122)
{
cout<<"输入的不是字母,重新输入:
"<cin>>ch;
}
#ifLETTER1ch>=65&&ch<=90
ch+=32;
cout<<"转换成小写字母为:
"<#else
a-=32;
cout<<"转换成大写字母为:
"<#endif
return0;
}
2)、运行结果
3、思考和扩展
一般情况下,源程序中所有的行都参加编译。
但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。
有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。
由条件编译的形式:
#ifdef标识符
程序段1
#else
程序段2
#endif
它的作用是:
当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2。
3.5实验五指针和引用(2012-10-21第十周)
题目1程序分析
1、分析