第六章:函数与宏定义

C程序设计实验报告

姓名:廖锦丽 实验地点:一教522 实验时间:5月27日

一、实验目的与要求

1.掌握函数的定义方法和调用规则。
2.掌握C语言程序中主调函数和被调函数之间进行数据传递的规则。
3.了解函数的返回值及其类型,并正确使用。
4.了解局部变量和全局变量的作用域及存储分类关系理解变量存在性和可见性的概念。
5.练习递归函数的使用。
6.理解宏的概念,掌握定义无参宏和带参宏的方法。
7.理解文件的概念并掌握其用法。
8.理解内部函数和外部函数,掌握外部函数的编译和连接方法。

二、实验内容

1.实验3.3.1-1
(1)问题描述:
已知三角形的三条边,求三角形的面积。
(2)实验代码:

c
#include<stdio.h>
#include<math.h>
float area(float a,float b,float c)
{float s,p,area;
	s=(a+b+c)/2;
	p=s*(s-a)*(s-b)*(s-c);
	area=sqrt(p);
	return (area);
}
main()
{
	float a,b,c,ts;
	printf("请输入三条边数值:例如3,4,5\n") ;
	scanf("%f,%f,%f",&a,&b,&c);
	ts=area(a,b,c);
	if(b+c>a&&a+c>b&&a+b>c)
	printf("三角形面积area=%f\n",ts);
	else printf("Data error!");
}

(3)问题分析:
此题运用到了函数的定义与调用,在main函数中可多次调用函数,调用规则是<变量=函数>。在判断是否符合三角形的三边关系时应把"b+c>a&&a+c>b&&a+b>c"都写上。

2.实验6.3.1-2
(1)问题描述:
求N的阶乘。
(2)实验代码:

c
#include<stdio.h>
int function(int i)
{
    static long f=1;//static为局部静态变量,局部静态变量具有继承性 
    f=f*i;
    return f;
}
main()
{
    long product;
    int i,n;
    printf("请输入n的值:\n");//由于product位数有限,因此n的值不能取过大 
    scanf("%d",&n);
    for(i=1;i<=n;i++)
       {
	product=function(i);
	printf("%d的阶乘是%d\n",i,product);
	}
} 

(3)问题分析:
static为局部静态变量,局部静态变量具有继承性,当n的值输入过大时,程序结果会出现负数,最后会出现0,这是因为定义的product为long int的数据类型,它占了8个字节,64位,当结果位数超过64位时,得到的结果会出现错误。

3.实验6.3.2-2
(1)问题描述
利用复化梯形公式计算定积分
1)编写一个函数sab(a,b,n)其功能为利用复化梯形公式计算定积分,其中n为对区间[a,b]的等分数,要求该函数在一独立的文件中。
2)编织一个主函数及计算被积函数值的函数f(x),在主函数中调用1)中函数sab.h计算并输出下列积分值:
s=f [-1,1] x2ex dx 取n=10。
3)编制另一个主函数及计算被积函数值的函数f(x),在主函数中利用sab计算并输出下列积分值
s=f [-1,1] 1/(1+25x^2) dx 取n=8。
4)要求画出模块sab(a,b,n)的流程图。
则复化梯形公式为:s=h[f(a)+f(b)]/2+h
f(xk)[k=1,n-1]
其中h=(b-a)/n,xk=a+kh。
(2)实验代码:

c
/*利用复化梯形公式计算定积分*/ 
#include<stdio.h>
double f(double x);
double sab(double a,double b,int n)
{
	double h,result,x1,x2,x3=0,t;
	int k; 
	h=(b-a)/n;
	x1=f(a);
	x2=f(b);
	for(k=1;k<=n-1;k++)
	{
		t=a+k*h;
		x3+=f(t);
	}
	result=h*(x1+x2)/2+h*x3;
	return result;
 } 
c
/*计算pow(x,2)*exp(x)的定积分*/
#include<stdio.h>
#include<math.h>
#include"sab.h"
double f(double x)
{
	double result;
	result=pow(x,2)*exp(x);
	return result;
 } 
 main()
 {
 	double a,b,result;
 	int n;
 	printf("Please input double a,b and integer n:\n");
 	scanf("%lf%lf%d",&a,&b,&n);
 	result=sab(a,b,n);
 	printf("sab(%lf,%lf,%d)=%f",a,b,n,result);
 }
c
/*计算1/(25+x*x)的定积分*/
#include<stdio.h>
#include<math.h>
#include"sab.h"
double f(double x)
{
	double result;
	result=1/(25+x*x);
	return result;
 } 
 main()
 {
 	double a,b,result;
 	int n;
 	printf("Please input double a,b and integer n:\n");
 	scanf("%lf%lf%d",&a,&b,&n);
 	result=sab(a,b,n);
 	printf("sab(%lf,%lf,%d)=%f",a,b,n,result);
 }

(3)问题分析:
Ⅰ、首先需要设计一个sab.h的文件,一定要命名sab.h,因为后面需要引用这个文件.
Ⅱ、准确理解#include<>和#include“”的区别,当include后是<>时,优先引用库函数,当include后为“”时,优先引用自己的文件.
Ⅲ、double对应的格式字符是%lf。

4.实验6.3.2练习三
(1)问题描述:
1.编制计算Ackerman函数的递归函数Ack(n,x,y);
2.编写一个主函数,调用Ack(n,x,y)计算函数;
3.函数包括:输入提示,数据合理性判断语句。
(2)实验代码:

c
#include<stdio.h>
int Ack(int n,int x,int y)
{
	int a;
	if(n==0)
	a=x+1;
	else if(n==1&&y==0)
	a=x;
	else if(n==2&&y==0)
	a=0;
	else if(n==3&&y==0)
	a=1;
	else if(n>=4&&y==0)
	a=2;
	else if(n!=0&&y!=0)
	a=Ack(n-1,Ack(n,x,y-1),x);
	return a;
}
int main()
{
	int n,x,y,result;
loop:
	printf("Please input n,x,y:\n");
	scanf("%d%d%d",&n,&x,&y);
	if(n<0||y<0)
	{
	printf("输入不合法,请重新输入:\n");
	}
	result=Ack(n,x,y);
	printf("Ack(%d,%d,%d)=%d\n",n,x,y,result);
		
}

(3)问题分析:
递归函数的实现需要用到Xn=X*X(n-1)的计算思想。

##三、辗转相除法
欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式gcd(a,b) = gcd(b,a mod b)。
欧几里得算法是用来求两个正整数最大公约数的算法。古希腊数学家欧几里得在其著作《The Elements》中最早描述了这种算法,所以被命名为欧几里得算法。
假如需要求 1997 和 615 两个正整数的最大公约数,用欧几里得算法,是这样进行的:
1997 / 615 = 3 (余 152)
615 / 152 = 4(余7)
152 / 7 = 21(余5)
7 / 5 = 1 (余2)
5 / 2 = 2 (余1)
2 / 1 = 2 (余0)
至此,最大公约数为1
以除数和余数反复做除法运算,当余数为 0 时,取当前算式除数为最大公约数

##四、小结
本章主要学习了函数的定义,函数的调用以及函数的声明。而函数的调用中有一个很重要的递归调用,递归是同类问题的逐步简化。递归函数设计的难点在于建立问题的数学模型,一旦建立了正确的递归数学模型,就可以很容易地编写出递归函数。

posted @ 2021-06-03 18:53  锦书予你,不忘离人  阅读(98)  评论(1编辑  收藏  举报