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