第六章 函数和宏定义

C程序设计实验报告
实验项目:6.3.1~6.3.3 姓名:游文进
实验地点:实验教室524 实验时间:5.27

一、实验目的与要求
1.掌握函数的定义方法和调用规则。
2.掌握C语言程序中主调函数和被调函数之间进行数据传递的规则。
3.了解函数的返回值及其类型,并正确使用。

4.了解局部变量和全局变量的作用域及存储分类关系理解变量存在性和可见性的概念
5.练习递归函数的使用
6.理解宏的概念,掌握定义无参宏和带参宏的方法
7.理解文件的概念并掌握其用法

8.理解内部函数和外部函数,掌握外部函数的编译和连接方法


二、实验内容


6.3.1-1
已知三角形的三条边,求三角形的面积.

代码:

#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(a<b+c&&b<a+c&&c<a+b)
	printf("三角形面积area=%f\n",ts);
	else printf("Data error!");
}

结果图:
image
分析:选择这道题的原因是它很好的展示了函数的定义方法和调用规则,
首先先在main主函数前进行函数定义,也就是函数的“内容”,之后在main中调用函数,假设在main中有多个变量需要用到函数则可直接调用,调用规则是<变量=函数>。


6.3.1-2
求N的阶乘

代码:

#include<stdio.h>
#define N 5
long function(int i)
{
	static long f=1;
	f=f*i;
	return f;
}
main()
{
	long product;
	int i;
	for(i=1;i<=N;i++)
	{
		product=function(i);
		printf("%d的阶乘是%d\n",i,product);
	}
} 

结果图:
image
问题分析:
该题涉及到
1.宏定义的运用即#define 定义一个量的值,之后在main函数中为设定的值;
2.函数返回值类型符,确定了返回值的类型
3.变量的静态存储类型static,定义局部变量时,局部变量的值将被保留,若定义时没有赋初值,则系统会自动为其赋0值,该题定义累乘积为long,初始值为1.
注意调用函数时变量类型应以函数返回值类型相同.


6.3.2-2
利用复化梯形公式计算定积分

问题描述:
1)编写一个函数sab(a,b,n)其功能为利用复化梯形公式计算定积分,其中n为对区间[a,b]的等分数,要求该函数在一独立的文件中.
2)编织一个主函数及计算被积函数值的函数f(x),在主函数中调用1)中函数sab.h计算并输出下列积分值:
s=f [-1,1] x2*ex 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

头文件代码:

#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;//求H的值
	  x1=f(a);//求f(a)的值 
	 x2=f(b);//求f(b)的值 
	   for(k=1;k<=n-1;k++)//for循环的循环体 
	{
	     t=a+k*h;
	     x3=x3+f(t);
	 } 
	 result=h*(x1+x2)/2+h*x3;
	 return result;
}

我认为头文件是和<stdio.h>相同的函数,即模块化应用。
在编写代码的过程中我将两个主程序文件放进同一个文件夹中,而头文件sab放桌面中,程序报错了,我猜想三个文件要置于同一级目录中才可发挥作用。
对于头文件的编写,因为要调用f(x),所以应在头文件sab.h中进行函数声明。
6.3.2-1主文件一

#include<stdio.h>
#include<math.h>
#include"6.32的sab.h"
double f(double x)
{
    double result;
    result=x*x*exp(x);
    return result;
}
main()
{
    double a,b,result;
    int n;
    printf("please enter a & b & n: \n");
    scanf("%lf,%lf,%d",&a,&b,&n);
    result=sab(a,b,n);
    printf("sab(%lf,%lf,%d)=%lf",a,b,n,result);
    return 0;
}

结果图:
image
6.3.2-2主文件二

#include<stdio.h>
#include"6.32的sab.h"
double f(double x)
{
    double result;
    result=1/(25+x*x);
    return result;
}
main()
{
    double a,b,result;
    int n;
    printf("please enter a & b & n:");
    scanf("%lf,%lf,%d",&a,&b,&n);
    result=sab(a,b,n);
    printf("sab(%lf,%lf,%d)=%f",a,b,n,result);
    return 0;
}

结果图:
image


6.3.2练习三
*递归函数的设计方法
*检查与调试程序方法的运用
问题描述:
1.编制计算Ackerman函数的递归函数Ack(n,x,y)
2.编写一个主函数,调用Ack(n,x,y)计算函数
3.函数包括:输入提示,数据合理性判断语句,
程序代码:

#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;
}
main()
{
	int n,x,y,result;
	printf("please enter n & x & y: ");
	scanf("%d,%d,%d",&n,&x,&y);
	if(n<0)
	{
		printf("Data error! please enter again: ");
		 
			scanf("%d,%d,%d",&n,&x,&y);
			result=Ack(n,x,y);
			printf("Ack(%d,%d,%d)=%d\n",n,x,y,result);
	}
	else result=Ack(n,x,y);
		printf("Ack(%d,%d,%d)=%d\n",n,x,y,result);
}

程序分析:
*对于不同的数据,运用if语句设定不同回归条件,返还不同的值,
我发现对于输入的数据似乎是有限制的,输入较小的数字可以得出结果,对于较大的数据好似陷入了无限循环,无法得出结果。
结果图:
image
image
image
较大的数据所得效果:
image
对程序进行调试无法得出原因,是我菜了。


三、辗转相除法
简要介绍:
欧几里得算法又称辗转相除法,是指用于计算两个非负整数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 时,取当前算式除数为最大公约数,

所以就得出了 1997 和 615 的最大公约数 1。
image

----来自百度百科

四、实验小结
本章主要涉及到函数的编译定义和调用,我认为对于这类程序,最为重要的是函数的”内容“,最需要注意的是程序中变量的类型,无论是将函数写在头文件中还是main函数外,都是为了减少程序的代码量,使程序结构更加严谨,所以学好这里是很重要的。
五、近期个人总结
1.在这一段的学习过程中总感觉C语言并不是很难理解,但如果没有任何提示让我去从头到尾编写一个程序,从流程图,到代码设计,还是会比较困难,我认为是对问题的分析不够,还没养成设计思维,要多进行练习。
2.关于复习代码可能选择初级的题目从头分析一边,但关于程序的结构,语句的书写方法要点会再重点复习。

posted @ 2021-06-01 21:47  小白和小新呀  阅读(284)  评论(2编辑  收藏  举报