C語言程序設計實驗報告 (五)


C程序設計實驗報告

姓名:黃靜微  實驗地點:家  實驗時間:2020.04.21

實驗項目

6.3.1 練習1 編寫由三角形三邊求面積的函數
6.3.1 練習2 編寫求N階乘的函數
6.3.1 練習3 求兩個整數的最大公約數
6.3.1 練習4 打印輸出指定圖形
6.3.2 練習1 求500以內的所有親密數對
6.3.2 練習2 利用復化梯形公式計算定積分
6.3.3 練習1 編寫x的y次冪遞歸函數
HanoTower

一、實驗目的與要求

  • 熟悉C語言中定義函數的方法
  • 掌握通過“值傳遞”調用函數的方法
  • 練習遞歸函數的使用方法
  • 了解函數的返回值及其類型,並正確使用
  • 了解局部變量和全局變量的作用域與存儲分類的關系
  • 理解變量的存在性和可見性的概念

二、實驗內容

1、實驗練習:6.3.1 練習1 編寫由三角形三邊求面積的函數

問題的簡單描述: 編寫程序,從鍵盤輸入三角形的3條邊,調用三角形面積函數求出其面積,並輸出結果。
流程圖:

實驗代碼:

#include <math.h>
#include <stdio.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 x,y,z,ts;
 	scanf("%f,%f,%f",&x,&y,&z);
 	if((x+y>z)&&(x+z>y)&&(y+z>x))
 	{
 		ts=area(x,y,z);
 		printf("area=%f\n",ts);
	 }
	 else
	 printf("Data error!");
 }

問題分析: 這里主要是在判斷輸入的三個值是否能構成三角形三邊的問題上,把問題復雜化了,不需要同時判斷兩邊之和大於第三邊以及兩邊之差小於第三邊,所以只需要滿足其中一個就可以了,改正后代碼看起來會更加簡潔。
運行結果:

2、實驗練習:6.3.1 練習2 編寫求N階乘的函數

問題的簡單描述: 編寫函數,求出從主函數傳來的數值i階乘值,然后將其傳回主調函數並輸出。
流程圖

實驗代碼:

#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);
	}
}

問題分析: 在輸入for 循環語句的時候,將分號輸入成了逗號,編譯出現了下面的結果,將其改成分號就得到了正確的運行結果,值得注意的是,我們平時用的是int型變量,但int型變量只占兩個字節的空間,求得值太大就會裝不下,所以這里要用到long型變量。
錯誤編譯

運行結果:

3、實驗練習:6.3.1 練習3 求兩個整數的最大公約數

問題的簡單描述: 編寫程序,從鍵盤輸入兩個整數,調用gcd()函數求他們的最大公約數,並輸出結果。
流程圖

實驗代碼:

#include <stdio.h>
int gcd(int a,int b)
{
	int temp;
	int remainder;
	if(a<b)
	{
		temp=a;
		a=b;
		b=temp;
	}
	remainder=a%b;
	while(remainder!=0)
	{
		a=b;
		b=remainder;
		remainder=a%b;
	}
	return b;
}
main()
{
	int x,y;
	int fac;
	printf("Please input two integers:");
	scanf("%d,%d",&x,&y);
	fac=gcd(x,y);
	printf("The great common divisor is %d",fac);
}

問題分析: 這個問題關鍵是如何將輾轉相除法轉換為代碼得形式,這就需要對輾轉相除法有一定得理解,一開始沒有理解輾轉相除法的用法,所以寫的時候沒有頭緒,也不是很理解書上的流程圖,通過百度,得出輾轉相除法如果有兩個數a,b,如果a>b,a能被b整除,則最大公約數就是b,若a除b的余數為c,則繼續用b除c,如此反復操作,直到最后余數為0,則最后一個非0的除數就是a,b的最大公約數。了解了輾轉相除法的用法,結合教材流程圖再寫代碼思路更清晰。
運行結果:

4、實驗練習:6.3.1 練習4 打印輸出指定圖形

問題的簡單描述: 輸入整數n,輸出高度為n的等邊三角形,當n的值為5,等邊三角形為:

流程圖

實驗代碼:

#include <stdio.h>
trangle(int n)
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n-i;j++)
		{
			printf(" ");
		}
		for(j=0;j<=2*i;j++)
		{
			printf("*");
		}
		putchar('\n');
	}
}
main()
{
	int n;
	printf("Please input a integer:");
	scanf("%d",&n);
	printf("\n");
	n=trangle(n);
}

問題分析: 這個程序和第五個章用for循環及其嵌套來三角形打印問題有相似之處,需要先理解n,i,j各代表的是什么,這里n表示行,i表示列,而用j表示*的個數,寫這個程序對前面for循環進行了復習,同時調用trangle()函數來輸出三角形鞏固了本章的知識。
運行結果:

5、實驗練習:6.3.2 練習1 求500以內的所有親密數對

問題的簡單描述: 若正整數A的所有因子(包括1但不包括自身,下同)之和為B,而B的因子之和為A,則稱A和B為一對親密數。例如,6的因子之和為1+2+3=6,因此6與6為一對親密數(即6自身構成一對親密數);又如,220的因子之和為1+2+4+5+10+11+20+22+44+55+110=284,而284的因子之和為1+2+4+71+142=220,因此,220與284為一對親密數。
求500以內的所有的親密數對。
流程圖:

實驗代碼:

#include <stdio.h>
int facsum(int m)
{
	int sum=1,f=2;
	while(f<=m/2)
	{
		if(m%f==0)
		sum=sum+f;
		f++;
	}
	return sum;
}
main()
{
	int m=3,n,k;
	while(m<=500)
	{
		n=facsum(m);
		k=facsum(n);
		if(m==k&&m<=n)
		printf("%d,%d\n",m,n);
		m++;
	}
}

問題分析: 親密對數有點不好理解,感覺如果沒有教材上的流程圖,自己寫這個代碼會比較困難,也想不到要先把一個數的因子累加,再把求出的因子和作為返回值,看返回后得出的第二個因子之和是否與之前的因子之和相等。
運行結果:

6、實驗練習:6.3.2 練習2 利用復化梯形公式計算定積分

問題的簡單描述:
(1)編制一個函數sab(a,b,n),其功能為利用復化梯形公式計算定積分

其中n為對區間[a,b]的等分數。要求該函數在一個獨立的文件中.
(2)編制一個主函數以及計算被積函數值的函數f(x),在主函數中調用(1)中的函數sab(a,b,n)計算並輸出下列積分值

要求主函數與函數f(x)在同一文件中。
(3)編制另一個主函數以及計算被積函數值的函數f(x),在主函數中調用(1)中的函數sab(a,b,n)計算並輸出下列積分值。

同樣要求主函數與函數f(x)在同一文件夾中,
(4)要求畫出模塊sab()的流程圖。
設定積分為:

則復化梯形求積公式為:

其中
流程圖:

實驗代碼:

/*sab.h*/
#include <stdio.h>
double f(double x);
double sab(double a,double b,int n)
{
	double h,result,x1,x2,x3=0,t,k;
	h=(b-a)/n;
	x1=f(a);
	x2=f(b);
	for(k=1;k<=n-1;k++)
	{
		t=a+k*h;
		x3=x3+f(t); 
	}
	result=h*(x1+x2)/2+h*x3;
	return result;
}
/*6.3.2-2.2.c*/
#include <stdio.h>
#include <math.h>
#include "sab.h"
double f(double x)
{
	double result;
	result=x*x*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)=%lf",a,b,n,result);
}
/*6.3.2-2.3.c*/
#include <stdio.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("Pleaase 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)=%lf",a,b,n,result);
 } 
 

問題分析: 不是很理解關於頭文件名和文件調用,也不知道#include“sab.h”是對函數文件的調用,程序編譯運行的時候因為我對編寫的頭文件的命名不是sab.h,導致編譯一直報錯,經過老師的直播講解,對文件調用問題更了解了一點,沒有那么懵逼,我理解的就是這種用法就相當於函數的調用,多個程序用到這個算法的話就可以直接用這個頭文件。
運行結果:


7、實驗練習:6.3.3 練習1 編寫x的y次冪遞歸函數

問題的簡單描述: 編寫程序,分別從鍵盤輸入數據x和y,計算x的y次冪並輸出。
流程圖:

實驗代碼:

#include <stdio.h>
long getpower(int x,int y)
{
	if(y==1)
	return x;
	else
	y=x*getpower(x,y-1);
}
main()
{
	int num,power;
	long answer;
	printf("輸入一個數:");
	scanf("%d",&num);
	printf("輸入冪次方:");
	scanf("%d",&power);
	answer=getpower(num,power);
	printf("%d^%d=%ld\n",num,power,answer);
}

問題分析: 按照函數的定義寫代碼基本上沒什么問題,一開始沒注意answer是長型的,用的%d,運行失敗,改成%ld就可以了。
運行結果:

8、實驗練習:HanoTower

問題的簡單描述描述: 三根柱子A、B、C,在A柱上按大小依次放着n個中間有孔的盤子,將這n個盤子從A柱移到C柱,移動過程中可借助B柱,每次只能移動一個盤子,大盤子在小盤子的下面,如何以最少的步驟完成?
實驗代碼:

#include <stdio.h>
void HanoTower(unsigned n,char tower_A,char tower_B,char tower_C);
void move(char tower1,char tower2);
int steps=0;
void main()
{
	unsigned n;
	printf("Please enter the number of disk:\n");
	scanf("%d",&n);
	printf("The steps of move:\n");
	HanoTower(n,'A','B','C');
	printf("The Total steps are:%d\n",steps);
}
void HanoTower(unsigned n,char a,char b,char c)
{
	steps++;
	if(n==1)
	    move(a,c);
	else
	{
	    HanoTower(n-1,a,c,b);
		move(a,c);
		HanoTower(n-1,b,a,c);	
	}
}
void move(char tower1,char tower2)
{
	printf("from \t%c-->\t%c\n",tower1,tower2);
}

問題分析: 首先要先理解漢諾塔游戲的意思,一開始沒有理解漢諾塔的步驟,就很難想到怎樣用遞歸寫代碼,要調用函數將盤子借助B柱移動到C柱,這個函數比較難想到,看了教材才理解,寫這個程序也意識到要再理解一下遞歸算法和遞歸原理。
運行結果:

四、實驗小結

  這次實驗的實驗項目比較多,還是要理解遞歸函數的定義才能更好地根據題目要求寫出代碼,因為有的代碼難一點,很依賴教材上的流程提示,自己獨立地想那個程序可能會很懵,不知道怎么寫,所以在編寫程序之前還是要自己想一下思路,嘗試一下能不能自己解決問題。在寫的時候經常犯小錯誤,所以如果編譯對了,運行不到之前結果就要自己檢查一下,標點符號,數據類型都要注意一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM