一、复习题
1. 使用函数的三个步骤是什么?
答:
- 函数声明
- 函数定义
- 调用函数
2. 请创建与下面的描述匹配的函数原型。
答:
// 函数声明
a. void igor();
b. float tofu(int i);
c. double mpg(double d1, double d2);
d. long summation(long arr[], int size);
e. double doctor(const char* str);
f. void ofcourse(boss bs);
g. char* plot(map* pm);
函数声明可以省略函数名,数组既可以使用数组表示法,也可以使用指针表示法(推荐数组表示法)。
3. 编写一个接受3个参数的函数,3个参数分别为int数组名、数组长度和一个int值,并将数组的所有元素设置为该int值。
答:
// 函数声明
void set_arr(int arr[], int size, int set);
int main()
{
// 操作
...
return 0;
}
// 函数定义
void set_arr(int arr[], int size, int set)
{
// 遍历数组,把每个元素的值设置为set
for (int i = 0; i < size; ++i)
{
arr[i] = set;
}
}
4. 编写一个接受3个参数的函数,3个参数分别为指向数组区间中的第一个元素的指针,指向数组区间中最后一个元素后面的指针已经一个int值,并将数组的每个元素设置为该int值。
答:
// 函数声明
void set_arr(int *begin, int *end, int set);
int main()
{
// 操作
...
return 0;
}
// 函数定义
void set_arr(int *begin, int *end, int set)
{
// 遍历数组,把每个元素的值设置为set
while (begin < end)
{
*begin = set;
}
}
5. 编写以double类型的数组名和长度最为参数并返回该数组中最大值的函数。该函数不应该修改数组的内容。
答:
// 函数声明
double find_max(double arr[], int size);
int main()
{
// 操作
...
return 0;
}
// 函数定义
double find_max(double arr[], int size)
{
// 让数组第一个元素和剩余元素比较,找出最大值
int max = arr[0];
for (int i = 1; i < size; ++i)
{
if (arr[i] > max)
max = arr[i];
}
// 返回数组最大值
return max;
}
6. 为什么不对类型为基本类型的函数参数使用const限定符?
答:在C++中参数传递是以值传递的方式实现的。int、double等基本类型传参,函数中使用的形参是实参的副本,形参改变不会影响实参。而数组、指针等复合类型传参,传递的是实参的地址,函数中的形参可以通过传入的地址改变实参。所以,基本类型不需要使用const限定符,而数组、指针等复合类型在需要的时候可以通过const限定符保护原数据。(这个东西不好讲,每个人都有自己的理解,理解了大概意思就行,在后面学习的过程中会慢慢理解的)。
7. C++程序可以使用哪三种C风格字符串?
答:
1)以空字符结尾存储在字符数组中的字符串
2)双引号标识的字符串常量
3)指向char类型的指针代表的字符串
8. 编写一个函数,其原型如下。
int replace(char* str, char c1, char c2);
该函数将字符串中所有的c1都替换为c2,并返回替换次数。
答:
// 函数声明
int replace(char *str, char c1, char c2);
int main()
{
// 操作
...
return 0;
}
// 函数定义
int replace(char *str, char c1, char c2)
{
int times = 0; // 记录交换次数
// 遍历整个字符串,发现c1就用c2替换,并记录替换次数
while (*str)
{
if (*str == c1)
{
// 交换并记录次数
*str = c2;
++times;
}
// 下一个字符
++str;
}
// 返回替换次数
return times;
}
9. 表达式*"pizza"的含义是什么?“taco”[2]呢?
答:在C++中,双引号表示的字符串常量实际上代表的是第一个字符的地址,所以*“pizza"代表字符p,而"taco”[2]是字符串的数组表示法,代表字符c。
10. C++允许按值传递结构体,也允许传递结构体的地址。如果glitz是一个结构体变量,如何按值传递它?如何传递它的地址?这两种方法有何利弊?
答:
1)值传递:直接将变量名传递给函数——glitz
优点:使用原数据的副本,保护原数据。
缺点:拷贝过程消耗时间和空间。
2)传地址:&glitz
优点:直接使用原数据,节省时间和空间。
缺点:不能保护原数据,除非使用const限定符。
11. 函数judge()的返回类型为int,它将以一个函数的地址作为参数,以const char指针作为参数,返回一个int值。请编写judge()函数的原型。
答:
// 函数声明
int judge(int (*pf)(const char*));
12. 假设有如下结构体声明。
// application结构声明
struct application{
char name[30];
int credit_tatings[3];
}
a. 编写一个函数,它以application结构体作为参数,并显示该结构体的内容。
b. 编写一个函数,它以application结构体的地址作为参数,并显示该结构体的内容。
答:
// a.函数声明
void print1_struct(application app);
// b.函数声明
void print_struct(application *papp);
int main()
{
// 操作
...
return 0;
}
// a.函数定义
void print1_struct(application app)
{
cout << app.name << endl;
for (int i = 0; i < 3; ++i)
cout << app.credit_ratings[i] << endl;
}
// b.函数定义
void print2_struct(application papp)
{
cout << app.name << endl;
for (int i = 0; i < 3; ++i)
cout << app.credit_ratings[i] << endl;
}
13. 假设函数f1()和f2()的原型如下。
void f1(applicant *a);
const char *f2(const applicant *a1, const applicant *a2);
请将p1与p2分别声明为指向f1和f2的指针…。
答:
// 用typedef简化类型声明
typedef void (*ptype1)(applicant *a);
typedef const char* (*ptype2)(const applicant *a1, const applicant *a2);
// 声明
ptype1 p1 = f1;
ptype2 p2 = f2;
ptype1 ap[5];
ptype2 (*pa)[10];
二、编程练习
1. 编写一个程序,不断要求用户输入两个数,直到其中一个为0。对于每两个数,程序将使用一个函数来计算它们的调和平均数,并将结果返回给main(),而后者将报告结果。调和平均数是倒数平均值的倒数,计算公式如下。
调和平均数 = 2.0xy/(x+y)
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 函数声明
double calculate_harmonic(int n1, int n2); // 计算两个数的调和平均数
int main()
{
int n1, n2; // 存储输入的两个数
// 输入
cout << "Please enter two number: ";
cin >> n1 >> n2;
while (n1 != 0 && n2 != 0) // 有一个数为0就停止输入
{
// 计算
double harmonic = calculate_harmonic(n1, n2);
// 显示
cout << "Harmonic: " << harmonic << endl;
// 下一组数
cout << "Please enter the next two number: ";
cin >> n1 >> n2;
}
return 0;
}
// 函数定义
double calculate_harmonic(int n1, int n2) // 计算两个数的调和平均数
{
return 2.0 * n1 * n2 / (n1 + n2);
}
2. 编写一个程序,要求用户输入最多10个高尔夫成绩,并将其存储在一个数组中。程序允许用户提早结束输入,并在一行上显示所有成绩,然后报告平均成绩。请使用三个数组处理函数,来分别输入、显示和计算平均成绩。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 函数声明
int input(double scores[]); // 输入高尔夫成绩
double calc_average(const double scores[], const int size); // 计算平均成绩
void print(const double scores[], const int size); // 打印成绩
int main()
{
// 输入成绩并存储成绩数量
double scores[10];
int size = input(scores);
// 计算平均值成绩
double average = calc_average(scores, size);
// 按格式输出
cout << "Scores: ";
print(scores, size);
cout << "Average: " << average << endl;
return 0;
}
// 函数定义
int input(double scores[]) // 输入高尔夫成绩
{
cout << "Please enter your golf score(-1 to quit):" << endl;
int num = 0; // 记录输入成绩数量
for (int i = 0; i < 10; ++i)
{
cout << i + 1 << ": ";
cin >> scores[i];
// 输入-1结束输入
if (scores[i] == -1)
break;
// 计数
++num;
}
return num;
}
double calc_average(const double scores[], const int size) // 计算平均成绩
{
double sum = 0; // 存储总成绩
// 计算总成绩
for (int i = 0; i < size; ++i)
{
sum += scores[i];
}
// 计算平均成绩并返回
double average = sum / size;
return average;
}
void print(const double scores[], const int size) // 打印成绩
{
// 遍历数组,打印成绩
for (int i = 0; i < size; ++i)
{
cout << scores[i] << " ";
}
cout << endl;
}
3. 下面是一个结构体声明。
// box结构声明
struct box{
char maker[40];
float height;
float width;
float length;
float volume;
}
a. 编写一个函数,按值传递box结构体,并显示每个成员的值。
b. 编写一个函数,传递box结构体的地址,并将volume成员设置为其他三位长度的乘积。
c. 编写一个使用这两个函数的简单程序。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// box结构声明
struct box
{
char maker[40];
float height; // 高
float width; // 宽
float length; // 长
float volume; // 体积
};
// 函数声明
void print_box(box b); // 打印box结构体
void calc_volume(box* pb); // 计算box的成员volume
int main()
{
// 创建一个box结构变量并初始化
box box1 = { "cat", 5, 5, 5 }; // volume未初始化,编译器设置为0
// 计算volume
calc_volume(&box1);
// 打印
print_box(box1);
return 0;
}
// 函数定义
void print_box(box b) // 打印box结构体
{
cout << "Maker: " << b.maker << endl;
cout << "Height: " << b.height << endl;
cout << "Width: " << b.width << endl;
cout << "Length: " << b.length << endl;
cout << "Volume: " << b.volume << endl;
}
void calc_volume(box* pb) // 计算box的成员volume
{
pb->volume = pb->height * pb->width * pb->length;
}
4. 许多州的彩票发行机构使用如程序清单7.4所示的简单彩票玩法的变体。…。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 函数声明
long double probability(double total, double special, double choice); // 计算中彩票头奖的概率
int main()
{
double total, special, choice; // 存储总个数,特殊个数,选择个数
// 输入
cout << "请输入总号码个数(输入-1停止): ";
cin >> total;
while (total != -1)
{
cout << "请输入特殊号码的区间为1-多少: ";
cin >> special;
cout << "请输入选择域号码的个数: ";
cin >> choice;
cout << "中彩票头奖的概率为: ";
long double proba = 1 / probability(total, special, choice);
cout << proba << endl;
}
// 结束
cout << "Done." << endl;
return 0;
}
// 函数声明
long double probability(double total, double special, double choice) // 计算中彩票头奖的概率
{
// 计算概率
long double proba = 1.0L;
for (long double i = choice, j = total; i > 0; --i, --j)
{
proba *= j / i;
}
return proba * special;
}
5. 定义一个递归函数,该函数接受一个整数参数,并返回该参数的阶乘。…。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 函数声明
long long factorial(int n); // 返回n的阶乘
int main()
{
// 输入
int n;
cout << "Please enter a number(-1 to quit): ";
cin >> n;
while (n != -1)
{
// 计算并输出
cout << "It's factorial: " << factorial(n) << endl;
// 下一个数
cout << "The next number: ";
cin >> n;
}
return 0;
}
// 函数声明
long long factorial(int n) // 返回n的阶乘
{
// 递归
if (n == 1 || n == 0) // 0和1的阶乘为1
return 1;
return n * factorial(n - 1);
}
6. 编写一个程序,它使用下列函数。
a. Fill_array()以一个double类型数组的名称和长度作为参数。它提示用户输入double值,并将这些值存储到数组中。当数组被填满或者用户输入非数字时,输入将停止,并返回实际输入了多少个数字。
b. Show_array()以一个double型数组的名称和长度作为参数,并显示该数组的内容。
c. Reverse_array()以一个double型数组的名称和长度作为参数,并将存储在数组中的值顺序反转。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 符号常量声明
const int SIZE = 10;
// 函数声明
int Fill_array(double arr[], const int size); // 填充数组,返回实际填充个数
void Show_array(const double arr[], const int length); // 显示数组
void Reverse_array(double arr[], const int length); // 将数组反转
int main()
{
// 创建数组
double arr[SIZE] = { 0 };
// 输入
int length = Fill_array(arr, SIZE);
// 显示数组
Show_array(arr, length);
// 反转数组
Reverse_array(arr + 1, length - 2); // 不反转数组第一位和最后一位
// 显示数组
Show_array(arr, length);
return 0;
}
// 函数定义
int Fill_array(double arr[], const int size) // 填充数组,返回实际填充个数
{
double input; // 存储输入的数
int length = 0; // 存储输入个数
cout << "Enter a number: ";
while (cin >> input && length < size) // 输入非数字或者数组满了停止输入
{
// 存储并计数
arr[length] = input;
++length;
// 输入下一个数
cout << "Next number: ";
}
// 返回输入个数
return length;
}
void Show_array(const double arr[], const int length) // 显示数组
{
for (int i = 0; i < length; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
void Reverse_array(double arr[], const int length) // 将数组反转
{
// 记录数组首尾下标
int left = 0;
int right = length - 1;
while (left < right)
{
// 交换
double temp = arr[right];
arr[right] = arr[left];
arr[left] = temp;
// 下一组
++left;
--right;
}
}
7. 修改程序清单7.7中的三个数组处理函数,使之使用两个指针来表示区间。…。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 符号常量声明
const int Max = 5;
// 函数声明
double* fill_array(double* begin, const int limit); // 填充数组
void show_array(double* begin, double* end); // 打印数组
void revalue(double* begin, double* end, const double n); // 数组每个元素乘以n
int main()
{
// 创建数组
double arr[Max];
// 填充并接收数组结尾地址
double* end = fill_array(arr, Max);
// 打印数组
show_array(arr, end);
// 数组每个元素乘以n
double n;
cout << "请输入数组缩放因子: ";
cin >> n;
revalue(arr, end, n);
// 打印
cout << "缩放后: " << endl;
show_array(arr, end);
cout << "Done." << endl;
return 0;
}
// 函数定义
double* fill_array(double* begin, const int limit) // 填充数组
{
double input; // 存储输入
int i = 0; // 记录数组的长度
for (i = 0; i < limit; ++i)
{
// 输入
cout << "Enter value #" << i + 1 << ": ";
cin >> input;
if (!cin) // 非法输入
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; input process terminated." << endl;
}
else if (input < 0)
break;
// 存储
*(begin + i) = input;
}
return begin + i;
}
void show_array(double* begin, double* end) // 打印数组
{
while (begin != end)
{
cout << *begin << " ";
++begin;
}
cout << endl;
}
void revalue(double* begin, double* end, const double n) // 数组每个元素乘以n
{
while (begin != end)
{
*begin *= n;
++begin;
}
}
8. 在不使用array类的情况下完成程序清单7.15所做的工作。编写两个这样的版本。
a. 使用const char数组存储表示季度名称的字符串,并使用double型数组存储开支。
b. 使用const char数组存储表示季度名称的字符串,并使用一个结构体,该结构体有一个成员,即一个用于存储开支的double数组。这种类的设计与使用array类的设计基本类似。
a. 部分
// 头文件
#include <iostream>
// 标准名称空间
using namespace std;
// 符号常量声明
const int Seasons = 4;
const char* pseasons[4] = { "Spring", "Summer", "Fall", "Winter" };
// 函数声明
void fill(double arr[], int size); // 填充数组
void show(double arr[], int size); // 显示数组
int main()
{
double arr[Seasons];
// 填充数组
fill(arr, Seasons);
// 显示数组
show(arr, Seasons);
return 0;
}
// 函数定义
void fill(double arr[], int size) // 填充数组
{
for (int i = 0; i < size; ++i)
{
cout << "Enter " << pseasons[i] << " expenses: ";
cin >> arr[i];
}
}
void show(double arr[], int size) // 显示数组
{
double total = 0; // 存储一年的
for (int i = 0; i < size; ++i)
{
// 打印每季度
cout << pseasons[i] << ": $" << arr[i] << endl;
// 计算一年
total += arr[i];
}
// 打印一年
cout << "Total Expenses: $" << total << endl;
}
b. 部分
// 头文件
#include <iostream>
// 标准名称空间
using namespace std;
// 符号常量声明
const int Season = 4;
const char* Sname[Season] = { "Spring", "Summer", "Fall", "Winter" };
// Spend结构声明
struct Spend
{
double money[Season];
};
// 函数声明
void fill(double arr[], const int size); // 填充数组
void show(const double arr[], const int size); // 显示数组
int main()
{
// 创建Spend结构变量
Spend expenses;
// 填充数组
fill(expenses.money, Season);
// 显示数组
show(expenses.money, Season);
return 0;
}
// 函数声明
void fill(double arr[], const int size) // 填充数组
{
for (int i = 0; i < size; ++i)
{
cout << "Enter " << Sname[i] << " expenses: ";
cin >> arr[i];
}
}
void show(const double arr[], const int size) // 显示数组
{
cout << endl;
cout << "Expenses:";
cout << endl;
double total = 0; // 存储一年总花费
for (int i = 0; i < size; ++i)
{
// 显示每个季度
cout << Sname[i] << ":$ " << arr[i] << endl;
// 计算一年总花费
total += arr[i];
}
// 显示一年
cout << "Total Expenses:$ " << total << endl;
}
9. 请编写处理数组和结构体的函数。下面是程序的框架,请提供其中描述的函数,以完成该程序。
// 头文件
#include <iostream>
// 标准名称空间std
using namespace std;
// 符号常量声明
const int SLEN = 30;
// student结构声明
struct student
{
char fullname[SLEN]; // 全名
char hobby[SLEN]; // 爱好
int ooplevel;
};
// 函数声明
int getinfo(student pa[], int n); // 填充student数组
void display1(student st); // 值传递打印
void display2(const student* ps); // 地址传递打印
void display3(const student pa[], int n); // 数组传递打印
int main()
{
// 输入学生人数
cout << "Enter the 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);
cout << endl;
// 以两种传参方式打印每个学生的信息
for (int i = 0; i < entered; ++i)
{
display1(ptr_stu[i]); // 值传递
cout << endl;
display2(&ptr_stu[i]); // 传递地址
cout << endl;
}
// 打印整个数组
display3(ptr_stu, entered);
// 释放申请空间
delete[]ptr_stu;
cout << "Done." << endl;
return 0;
}
// 函数定义
int getinfo(student pa[], int n) // 填充student数组
{
int i; // 记录输入个数
cout << "请输入学生的信息(输入空行结束):" << endl;
for (i = 0; i < n; ++i)
{
cout << "第" << i + 1 << "位:" << endl;
cout << "姓名: ";
cin.getline(pa[i].fullname, SLEN);
// 输入空行
if (!cin)
{
// 重置输入
cin.clear();
// 清除无效输入
while (cin.get() != '\n')
continue;
// 结束输入
cout << "输入结束" << endl;
break;
}
cout << "爱好: ";
cin.getline(pa[i].hobby, SLEN);
cout << "ooplevel: ";
cin >> pa[i].ooplevel;
cin.get(); // 读取换行符
}
// 返回输入个数
return i;
}
void display1(student st) // 值传递打印
{
cout << "姓名: " << st.fullname << endl;
cout << "爱好: " << st.hobby << endl;
cout << "ooplevel: " << st.ooplevel << endl;
}
void display2(const student* ps) // 地址传递打印
{
cout << "姓名: " << ps->fullname << endl;
cout << "爱好: " << ps->hobby << endl;
cout << "ooplevel: " << ps->ooplevel << endl;
}
void display3(const student pa[], int n) // 数组传递打印
{
for (int i = 0; i < n; ++i)
{
cout << "第" << i + 1 << "位同学" << endl;
cout << "姓名: " << pa[i].fullname << endl;
cout << "爱好: " << pa[i].hobby << endl;
cout << "ooplevel: " << pa[i].ooplevel << endl;
cout << endl;
}
}
10. 设计一个名为calculate()的函数,它接受两个double值和一个指向函数的指针,而被指向的函数接受两个double参数,并返回一个double值。…。
// 头文件
#include <iostream>
// 标准名称空间
using namespace std;
// 函数声明
double calculate(double d1, double d2, double (*pf)(double, double)); // 通过函数指针调用函数计算
double add(double d1, double d2); // 加法
double mul(double d1, double d2); // 乘法
int main()
{
int n1, n2; // 存储输入的两个数
// 输入
cout << "请输入两个数(输入q停止): ";
while (cin >> n1 >> n2)
{
// 通过函数指针调用两个函数计算并输出
cout << "相加: " << calculate(n1, n2, add) << endl;
cout << "相乘: " << calculate(n1, n2, mul) << endl;
// 下一组
cout << "请输入两个数(输入q停止): ";
}
return 0;
}
// 函数定义
double calculate(double d1, double d2, double (*pf)(double, double)) // 通过函数指针调用函数计算
{
return pf(d1, d2);
}
double add(double d1, double d2) // 加法
{
return d1 + d2;
}
double mul(double d1, double d2) // 乘法
{
return d1 * d2;
}