C++ Primer Plus(第六版)程式設計練習答案 第7章 函式——C++的程式設計模組
本章所有程式設計練習的工程原始碼可在此處下載(點選開啟下載連結),供大家參考交流!
1. 編寫一個程式,不斷要求使用者輸入兩個數,直到其中的一個為0。對於每兩個數,程式將使用一個函式來計算它們的調和平均數,並將結果返回給main(),而後者將報告結果。調和平均數指的是倒數平均值的倒數,計算公式如下:
調和平均數=2.0*x*y/(x+y)
本題要求編寫一個函式,該函式接受的輸入引數為兩個int型別的數,函式內部計算這兩個數的調和平均數,然後將結果返回給main(),由main()來顯示該結果。對於輸入終止,題目設定的是當輸入中有一個數是0時,輸入就結束。這個輸入終止的功能只需要設定一個if判斷就可以完成了;另外對於呼叫函式,我們將輸入的迴圈放在main()裡面,然後判斷了沒有0之後,再把這兩個輸入的數作為引數來呼叫計算函式即可。
程式碼如下:
// 7.1.cpp: 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <iostream> using namespace std; double cal(int x, int y); int main() { int x, y; double ave; while (1) { cout << "Please enter two number:"; cin >> x >> y; if (x == 0 || y == 0) { cout << "Input terminated\nQuit\n"; break; } else { ave = cal(x, y); cout << "The harmonic average is " << ave << endl; } } system("pause"); return 0; } double cal(int x, int y) { double ave; ave = 2.0 * double(x * y) / (x + y); return ave; }
執行結果如下圖所示:
2. 編寫一個程式,要求使用者輸入最多10個高爾夫成績,並將其儲存在一個數組中。程式允許使用者提早結束輸入,並在一行上顯示所有成績,然後報告平均成績。請使用3個數組處理函式來分別進行輸入、顯示和計算平均成績。
本題要求編寫3個函式,分別用來輸入、顯示和計算平均成績,同時規定最多10個成績,但也可以允許提早結束輸入,對於這個功能,我們可以在提示使用者輸入時提示輸入一個特定字元以結束,而函式內部我們定義使用者輸入的內容為double型別,這樣一旦輸入char字元型,就會輸入失敗,接下來用一個if判斷來判斷輸入是否失敗就可以完成提早結束輸入了。對於顯示和計算函式,我們只需要把儲存成績的double陣列和陣列長度作為引數傳給函式,然後在函式內部使用for迴圈來進行顯示和計算就可以了。
程式碼如下:
// 7.2.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
const int Max = 10;
int input(double ar[], int limit);
void display(const double ar[], int n);
double cal(double ar[], int n);
using namespace std;
int main()
{
double scores[Max];
int size = input(scores, Max);
display(scores, size);
double ave;
ave = cal(scores, size);
cout << "\nThe average score is " << ave << endl;
system("pause");
return 0;
}
int input(double ar[], int limit)
{
int i;
double score;
cout << "Please enter the scores, 'q' to quit.\n";
for (i = 0; i < limit; i++)
{
cout << "Enter the score #" << (i + 1) << ": ";
cin >> score;
if (!cin)
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Input process terminated\nQuit\n";
break;
}
ar[i] = score;
}
return i;
}
void display(const double ar[], int n)
{
cout << "You entered " << n << " scores.\n";
cout << "The scores are:\n";
for (int i = 0; i < n; i++)
{
cout << ar[i] << "\t";
}
}
double cal(double ar[], int n)
{
double ave;
double sum = 0.0;
for (int i = 0; i < n; i++)
{
sum += ar[i];
}
ave = sum / n;
return ave;
}
執行結果如下圖所示:
程式碼中我寫的是提示使用者輸入q來退出輸入,下圖是使用者輸入q提早結束的情況:
下圖是輸入10個數之後自動輸出結果的情況:
3. 下面是一個結構宣告:
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
a. 編寫一個函式,按值傳遞box結構,並顯示每個成員的值。
b. 編寫一個函式,傳遞box結構的地址,並將volume成員設定為其他三維長度的乘積。
c. 編寫一個使用這兩個函式的簡單程式。
本題要求編寫兩個函式,一個用來按值傳遞結構,顯示資料;一個用來按地址傳遞結構,並計算資料;然後在main()中來呼叫這兩個函式完成功能。對於按值傳遞結構,我們就正常使用就可以了,比如以下語句:
box a;
cout << a.maker;
cout << a.height;
cout << a.width;
cout << a.length;
cout << a.volume;
就會正常輸出a這個box結構的maker, height, width, length, 和volume這些資料。
而對於按地址傳遞,宣告時應該寫成以下形式:
datatype func(box * a);
然後呼叫語句應是以下形式:
b = func(&a);
然後在函式內部,結構成員的使用要把.改成->,如以下形式:
vol = a->height * a->width * a->length;
以上語句就是用來計算體積的。
程式碼如下:
// 7.3.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
void display(box temp);
float cal(box * temp);
using namespace std;
int main()
{
cout << "The following is the example box.\n";
box temp;
cout << "Please enter the box maker: ";
cin >> temp.maker;
cout << "Please enter the height: ";
cin >> temp.height;
cout << "Please enter the width: ";
cin >> temp.width;
cout << "Please enter the length: ";
cin >> temp.length;
cout << "Please enter the volume: ";
cin >> temp.volume;
display(temp);
float vol;
vol = cal(&temp);
cout << "\nBut after the calculation, the volume of the box is " << vol << endl;
system("pause");
return 0;
}
void display(box temp)
{
cout << "\nThe maker of the box is " << temp.maker << "." << endl;
cout << "The height of the box is " << temp.height << "." << endl;
cout << "The width of the box is " << temp.width << "." << endl;
cout << "The length of the box is " << temp.length << "." << endl;
cout << "The volume of the box is " << temp.volume << "." << endl;
}
float cal(box * temp)
{
float vol;
vol = temp->height * temp->width * temp->length;
return vol;
}
執行結果如下圖所示:
4. 許多州的彩票發行結構都使用如程式清單7.4所示的簡單彩票玩法的變體。在這些玩法中,玩家從一組被稱為域號碼(field number)的號碼中選擇幾個。例如,可以從域號碼1~47中選擇5個號碼;還可以從第二個區間(如1~27)選擇一個號碼(稱為特選號碼)。要贏得頭獎,必須正確猜中所有的號碼。中頭獎的機率是選中所有域號碼的機率與選中號碼機率的乘積。例如,在這個例子中,中頭獎的機率是從47個號碼中正確選取5個號碼的機率與從27個號碼中正確選擇1個號碼的機率的乘積。請修改程式清單7.4,以計算中得這種彩票頭獎的機率。
本題要計算中頭獎的概率,其實就是計算47個數中選5個特定數的概率與27個數中選1個特定數的概率之積,我們只需要把47,5,27,1這四個數按值傳遞給單獨計算的函式,計算出結果之後再返回給main()顯示就可以了。
程式碼如下:
// 7.4.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
double cal(int num1, int num2, int bingo1, int bingo2);
const int Num1 = 47;
const int Num2 = 27;
const int Bingo1 = 5;
const int Bingo2 = 1;
int main()
{
cout << "Your Probability to win the first prize in this game is\t";
double pro;
pro = cal(Num1, Num2, Bingo1, Bingo2);
cout << pro << " !!!" << endl;
system("pause");
return 0;
}
double cal(int num1, int num2, int bingo1, int bingo2)
{
double pro, pro1, pro2;
pro1 = double(bingo1) / double(num1);
pro2 = double(bingo2) / double(num2);
pro = pro1 * pro2;
return pro;
}
執行結果如下圖所示:
5. 定義一個遞迴函式,接受一個整數引數,並返回該引數的階乘。前面講過,3的階乘寫作3!,等於3*2!,依此類推;而0!被定義為1。通用的計算公式是,如果n大於零,則n!=n*(n-1)!。在程式中對該函式進行測試,程式使用迴圈讓使用者輸入不同的值,程式將報告這些值的階乘。
本題要求編寫一個遞迴函式來計算階乘,由於階乘是累乘運算,所以需要迴圈多次地呼叫該遞迴函式,比如func(n)裡面就會呼叫func(n-1),這樣依次下去,然後規定好func(0)=1就可以了。在main()函式裡,我做了一些處理,首先是提示使用者輸入,q退出輸入,然後識別使用者輸入的是否是可接受的整數,其次判斷是否是非負數,然後都判決通過之後才會去呼叫遞迴函式。
程式碼如下:
// 7.5.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
int fac(int n);
using namespace std;
int main()
{
cout << "This program can calculate the factorial.\t'q' to quit." << endl;
int n;
int result;
while (1)
{
cout << "Please enter the number for factorial: ";
cin >> n;
if (!cin)
{
cout << "Input terminated.\nQuit\n";
break;
}
else if (n < 0)
{
cout << "Bad input, please enter a positive number!" << endl;
continue;
}
else if (n >= 0)
{
result = fac(n);
cout << "The factorial of " << n << " is " << result << endl;
}
}
system("pause");
return 0;
}
int fac(int n)
{
int result;
if (n == 0)
result = 1;
else
{
result = n * fac(n - 1);
}
return result;
}
執行結果如下圖所示:
6. 編寫一個程式,它使用下列函式:
Fill_array()將一個double陣列的名稱和長度作為引數。它提示使用者輸入double值,並將這些值儲存到陣列中。當陣列被填滿或使用者輸入了非數字時,輸入將停止,並返回實際輸入了多少個數字。
Show_array()將一個double陣列的名稱和長度作為引數,並顯示該陣列的內容。
Reverse_array()將一個double陣列的名稱和長度作為引數,並將儲存在陣列中的值的順序反轉。
程式將使用這些函式來填充陣列,然後顯示陣列;反轉陣列,然後顯示陣列;反轉陣列中除第一個和最後一個元素之外的所有元素,然後顯示陣列。
本題要求編寫3個函式,第一個函式用來提示使用者輸入,儲存輸入的值到陣列中,並判斷在輸入了非數字時停止輸入;第二個函式用來顯示陣列的內容;第三個函式用來將陣列中的數值的順序反轉。在main()裡面,我們按以下功能來依次呼叫以上三個函式,首先填充陣列並顯示,然後反轉陣列並顯示,然後反轉陣列中除第一個和最後一個元素之外的所有元素再顯示。所以前面都是正常呼叫函式,引數也是正常的引數,但是最後一個功能的時候,我們在呼叫反轉函式Reverse_array()時,使用的引數將有所變化,因為它要反轉的是除去第一個元素和最後一個元素之外的元素,所以長度肯定比之前小2,而且起始也比之前往後移了1位,所以我們最後一個呼叫應該是形如以下這樣的語句:
Reverse_array(ar + 1, size - 2);
程式碼如下:
// 7.6.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
int Fill_array(double ar[], int size);
void Show_array(double ar[], int size);
void Reverse_array(double ar[], int size);
using namespace std;
const int Max = 20;
int main()
{
cout << "Please enter the data of array. 'q' to quit.\n";
double ar[Max];
int size;
size = Fill_array(ar, Max);
Show_array(ar, size);
Reverse_array(ar, size);
cout << "\nAfter the reverse.";
Show_array(ar, size);
Reverse_array(ar, size);
cout << "\nAfter the reverse.";
Reverse_array(ar + 1, size - 2);
Show_array(ar, size);
cout << endl;
system("pause");
return 0;
}
int Fill_array(double ar[], int size)
{
int i;
double j;
int num;
for (i = 0; i < size; i++)
{
cin >> j;
if (!cin)
{
cout << "Input terminated.\nQuit.\n";
break;
}
else
{
ar[i] = j;
}
num = i + 1;
}
return num;
}
void Show_array(double ar[], int size)
{
int i;
cout << "\nThe array is:\n";
for (i = 0; i < size; i++)
{
cout << ar[i] << " ";
}
}
void Reverse_array(double ar[], int size)
{
int i;
double temp;
for (i = 0; i < (size / 2); i++)
{
temp = ar[i];
ar[i] = ar[size - 1 - i];
ar[size - 1 - i] = temp;
}
}
執行結果如下圖所示:
7. 修改程式清單7.7中的3個數組處理函式,使之使用兩個指標引數來表示區間。fill_array()函式不返回實際讀取了多少個數字,而是返回一個指標,該指標指向最後被填充的位置;其他的函式可以將該指標作為第二個引數,以標識資料結尾。
本題要求將正常的陣列處理函式,改為使用指標作引數來傳遞的函式,將按值傳遞陣列改為按地址傳遞陣列,同時把傳遞陣列長度的數改為標識資料結尾的指標。其實就完全只需要把程式清單7.7裡面的引數都改為指標式,對應地把對陣列資料和長度的操作都改為對指標的操作就可以了。
程式碼如下:
// 7.7-arrfun3.cpp: 定義控制檯應用程式的入口點。
// 7.7-arrfun3.cpp: array functions and const
#include "stdafx.h"
#include <iostream>
const int Max = 5;
double *fill_array(double *ar, double *limit);
void show_array(const double *ar, double *n);
void revalue(double r, double *ar, double *n);
int main()
{
using namespace std;
double properties[Max];
double *size = fill_array(properties, properties + Max);
show_array(properties, size);
cout << "Enter revaluation factor: ";
double factor;
cin >> factor;
revalue(factor, properties, size);
show_array(properties, size);
cout << "Done.\n";
system("pause");
return 0;
}
double *fill_array(double *ar, double *limit)
{
using namespace std;
double temp;
int i = 0;
double *p;
for (p = ar; p < limit; p++, i++)
{
cout << "Enter value#" << (i + 1) << ": ";
cin >> temp;
if (!cin)
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; input process terminated.\n";
break;
}
else if (temp < 0)
break;
*p = temp;
}
return p;
}
void show_array(const double *ar, double *n)
{
using namespace std;
int i = 0;
for (const double *p = ar; p < n; p++, i++)
{
cout << "Property #" << (i + 1) << ": $";
cout << *p << endl;
}
}
void revalue(double r, double *ar, double *n)
{
for (double *p = ar; p < n; p++)
*p *= r;
}
執行結果如下圖所示:
8. 在不使用array類的情況下完成程式清單7.15所做的工作。編寫兩個這樣的版本:
a. 使用const char*陣列儲存表示季度名稱的字串,並使用double陣列儲存開支。
b. 使用const char*陣列儲存表示季度名稱的字串,並使用一個結構,該結構只有一個成員——一個用於儲存開支的double陣列。這種設計與使用array類的基本設計類似。
程式清單7.15使用了array類來儲存季度的字串,對於開支並沒有專門儲存,而是直接輸入就使用了;本題則要求在此基礎上進行改良,得到兩個版本,第一個版本是使用const char*陣列儲存字串,使用double陣列儲存開支;第二個版本是使用const char*陣列儲存字串,使用結構儲存開支。
對於第一種情況,使用陣列來儲存開支,那麼我們在呼叫輸入函式和顯示函式的時候,也就按值傳遞陣列就可以了;對於第二種情況,使用結構來儲存開支,我們在呼叫輸入函式和顯示函式的時候,也可以直接按值傳遞,但為了練習,我使用了結構指標來完成任務。
第一個版本程式碼如下:
// 7.8.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
const int Seasons = 4;
const char * Snames[Seasons] = { "Spring", "Summer", "Fall", "Winter" };
void fill(double pa[]);
void show(double pa[]);
using namespace std;
int main()
{
double expenses[Seasons];
fill(expenses);
show(expenses);
system("pause");
return 0;
}
void fill(double pa[])
{
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> pa[i];
}
}
void show(double pa[])
{
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << pa[i] << endl;
total += pa[i];
}
cout << "Total Expenses: $" << total << endl;
}
執行結果如下圖所示:
第二個版本程式碼如下:
// 7.8-b.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
const int Seasons = 4;
struct ex
{
double expenses[Seasons];
};
const char * Snames[Seasons] = { "Spring", "Summer", "Fall", "Winter" };
void fill(ex * pa);
void show(ex * pa);
using namespace std;
int main()
{
ex pa;
fill(&pa);
show(&pa);
system("pause");
return 0;
}
void fill(ex * pa)
{
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> pa->expenses[i];
}
}
void show(ex * pa)
{
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << pa->expenses[i] << endl;
total += pa->expenses[i];
}
cout << "Total Expenses: $" << total << endl;
}
執行結果如下圖所示:
9. 這個練習讓您編寫處理陣列和結構的函式。下面是程式的框架,請提供其中描述的函式,以完成該程式。(相信大家書上都有題,這裡就不細細敲下來了)
本題需要編寫4個函式,其他內容都給你規定好了。
第一個函式getinfo(),一個結構體陣列,一個int型別引數,結構體陣列引數儲存了學生的姓名,愛好,oop等級這三個資訊,而int型別的引數則是輸入資料的數目的上界,也可以通過直接敲回車來提前結束輸入,否則就需要輸入到上界數目個資訊。
第二個函式display1(),該函式就只接受一個結構體引數,然後把結構體的內容顯示出來。
第三個函式display2(),該函式接受一個結構指標,然後顯示結構體內容。
第四個函式display3(),該函式接受結構體陣列和int型別引數,對應於getinfo()函式的兩個引數,然後把結構體的內容顯示出來。
程式碼如下:
// 7.9.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
const int SLEN = 30;
struct student {
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
int getinfo(student pa[], int n);
void display1(student st);
void display2(const student * ps);
void display3(const student pa[], int n);
int main()
{
cout << "Enter class size: ";
int class_size;
cin >> class_size;
while (cin.get() != '\n')
continue;
student * ptr_stu = new student[class_size];
int entered = getinfo(ptr_stu, class_size);
for (int i = 0; i < entered; i++)
{
display1(ptr_stu[i]);
display2(&ptr_stu[i]);
}
display3(ptr_stu, entered);
delete[] ptr_stu;
cout << "Done\n";
system("pause");
return 0;
}
int getinfo(student pa[], int n)
{
int count = 0;
for (int i = 0; i<n; i++)
{
cout << "Please enter the fullname:";
cin.getline(pa[i].fullname, 30);
cout << "Please enter the hobby:";
cin >> pa[i].hobby;
cout << "Please enter the ooplevel:";
cin >> pa[i].ooplevel;
cin.get();
count++;
}
cout << "Enter end!" << endl;;
return count;
}
void display1(student st)
{
cout << "\ndisplay1:\nFullName:" << st.fullname << "\nhobby:" << st.hobby
<< "\nooplevel:" << st.ooplevel << endl;
}
void display2(const student *ps)
{
cout << "\ndispaly2:\nFullName:" << ps->fullname << "\nhobby:" << ps->hobby
<< "\nooplevel:" << ps->ooplevel << endl;
}
void display3(const student pa[], int n)
{
cout << "\ndispaly3:" << endl;
for (int i = 0; i<n; i++)
cout << i << "::\nFullName:" << pa[i].fullname << "\nhobby:" << pa[i].hobby
<< "\nooplevel:" << pa[i].ooplevel << endl;
}
需要注意的是getinfo()函式裡面,由於要求輸入全名fullname,所以肯定要允許輸入多個單詞,所以對於char陣列要使用cin.getline()函式,而hobby和ooplevel的內容又是使用cin>>的方式輸入,所以必須在cin.getline()函式前面一個cin>>的後面加一句cin.get()函式來抵消掉由於二者聯合使用,而cin>>在前而導致的緩衝區內多出來的一個回車符,該問題在我寫的《C++ Primer Plus 第六版》的第5章練習題答案中有詳細描述(點選開啟連結)。
執行結果如下圖所示:
10. 設計一個名為calculate()的函式,它接受兩個double值和一個指向函式的指標,而被指向的函式接受兩個double引數,並返回一個double值。calculate()函式的型別也是double,並返回被指向的函式使用calculate()的兩個double引數計算得到的值。例如,假設add()函式的定義如下:
double add(double x, double y)
{
return x + y;
}
則下述程式碼中的函式呼叫將導致calculate()把2.5和10.4傳遞給add()函式,並返回add()的返回值(12.9);
double q = calculate(2.5, 10.4, add);
請編寫一個程式,它呼叫上述兩個函式和至少另一個與add()類似的函式。該程式使用迴圈來讓使用者成對地輸入數字。對於每對數字,程式都使用calculate()來呼叫add()和至少一個其他的函式。如果讀者愛冒險,可以嘗試建立一個指標陣列,其中的指標指向add()樣式的函式,並編寫一個迴圈,使用這些指標連續讓calculate()呼叫這些函式。提示:下面是宣告這種指標陣列的方式,其中包含三個指標:
double (*pf[3])(double, double);
可以採用陣列初始化語法,並將函式名作為地址來初始化這樣的陣列。
本題要求編寫一個calculate()函式來做計算,然後還有兩個具體計算的函式,一個add()已經給出來了,另一個我們可以就用sub()來做減法就可以了。題目說愛冒險可以用指標陣列,那麼我就冒險一把,使用這種指標陣列的方式來傳遞,其實只需要在給calculate()函式傳遞函式的時候使用指標陣列就可以了,不需要特別單獨去宣告這個指標陣列。
我編寫的程式是首先提示使用者輸入兩個數,判斷輸入的數是否符合要求,然後將這兩個數分別和add()函式及sub()函式組合形成兩組引數,分別使用這兩組引數呼叫calculate()函式,得到結果之後顯示出來。
程式碼如下:
// 7.10.cpp: 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
double add(double x, double y);
double sub(double x, double y);
double calculate(double x, double y, double (*func)(double x, double y));
using namespace std;
int main()
{
while (1)
{
cout << "Please enter two numbers, 'q' to quit: ";
double x, y;
double result;
cin >> x >> y;
if (!cin)
{
cout << "Input terminated.\nQuit.\n";
break;
}
double q = calculate(x, y, add);
double w = calculate(x, y, sub);
cout << x << " add " << y << " equals to " << q << endl;
cout << x << " minus " << y << " equals to " << w << endl;
}
system("pause");
return 0;
}
double add(double x, double y)
{
return x + y;
}
double sub(double x, double y)
{
return x - y;
}
double calculate(double x, double y, double (*func)(double x, double y))
{
double result;
result = (*func)(x, y);
return result;
}
由上述程式碼可以看出,使用題中所說的冒險的方法,其實也並不怎麼複雜,無非就是正常地傳遞函式變為傳遞函式指標而已。
執行結果如下圖所示:
本章所有程式設計練習的工程原始碼可在此處下載(點選開啟下載連結),供大家參考交流!