《C++ Primer Plus第6版中文版》学习笔记(第一 ~第六章)
《C++ Primer Plus第6版中文版》学习笔记(第七章)
http://download.csdn.net/detail/qq20004604/9381056
1.编写一个程序,不断要求用户输入两个数,直到其中的一个为0。对于每两个数,程序将使用一个函数来计算它们的调和平均数,并将结果返回给main(),而后者将报告结果。调和平均数指的是倒数平均数的倒数,计算公式如下:
调和平均数=2.0*x*y/(x+y)
答:
#include<iostream>
using namespace std;
double tiaohe(double, double); //用于计算调和平均数
double error(double,double); //用于检查输入错误
int main()
{
double a_1, a_2;
cout << "请输入两个数,系统将自动帮你计算这两个数的调和平均数。\n当输入 0 时,程序结束。" << endl;
while (cin)
{
cout << "数字1:";
cin >> a_1;
cout << "数字2:";
cin >> a_2;
double x = error(a_1, a_2);
if (x == 0)
{
cout << "你输入了数字0,程序结束。" << endl;
cin.sync();
cin.get();
return 0;
}
else if (x == 2)
{
cout << "你输入错误,请重新输入。" << endl;
continue;
}
else
{
cout << "你输入的两个数的调和平均数是:" << tiaohe(a_1, a_2) << endl << endl;
cout << "请再次输入两个数,结束请输入0" << endl;
}
cin.sync();
}
system("pause");
return 0;
}
double tiaohe(double a_1, double a_2)
{
double pingjunshu;
pingjunshu = 2.0*a_1*a_2 / (a_1 + a_2);
return pingjunshu;
}
double error(double m,double n)
{
if (m == 0)return 0; //如果输入为0时,返回0
else if (!cin)
{
cin.clear();
cin.sync();
return 2; //如果输入为错误时,清除错误标识,清空输入缓存,返回2
}
//如果m正常,则判断n
if (n == 0)return 0; //如果输入为0时,返回0
else if (!cin)
{
cin.sync();
return 2; //如果输入为错误时,清除输入缓存,返回2
}
else return 1; //如果输入正常,返回1
}
2.编写一个程序,要求用户输入最多10个高尔夫成绩,并将其存储在一个数组中。程序允许用户提早结束输入,并在一行上显示所有成绩,然后报告平均成绩。请使用3个数组处理函数来分别进行输入、显示和计算平均成绩。
答:
//高尔夫成绩
#include<iostream>
using namespace std;
double*input(void); //输入数组的函数,返回数组指针
void show(double*); //显示数组的函数,参数是指针
double mean_value(double*); //计算平均数的函数,参数是指针
int main()
{
double*m = input();
show(m);
double pingjun = mean_value(m);
cout << "平均成绩是: " << pingjun << endl;
system("pause");
return 0;
}
double* input(void) //输入成绩的函数
{
cout << "请输入你的高尔夫成绩,最多可以输入10个。输入负值或者输入非法字符时,结束输入。" << endl;
static double x[11];
double*m = x; //double指针指向数组x(准确的说是数组x的第一个成员)
int i;
for (i = 0;i < 10 && cin;i++)
{
cout << i + 1 << "#成绩: ";
cin >> x[i];
if (x[i] < 0)
{
break;
}
}
if (!cin) //假如输入错误,那么就是因为输入非法字符
{
i--; //于是i-1。因为输入非法字符时,a[i-1]是非法字符,
cin.clear();
cin.sync();
}
//假如正常跳出,那么如果输入0,则跳出,没有i++这个循环更新,于是是x[i]
//假如是输满了10个,那么i此时=10,x[i]是第11个数。
//将x[i]赋值为-1,作为检测数组结束的标识。
x[i] = -1;
return m; //返回指针m
}
void show(double*m) //显示成绩的函数
{
cout << "高尔夫成绩为:";
for ( ;*m >= 0;m++) //*m大于等于0,说明没有检测到数组结束标识,检测到结束标识的话,则自动结束。m++是指针每次移动一位
cout << *m << " "; //加空格,作为两次成绩之间的间隔
cout << endl;
}
double mean_value(double* m) //计算平均数的函数
{
int i;
double total = 0;
for (i = 0;*m >= 0;m++)
{
total = total + *m;
i++; //每加一次,说明成员多一个
}
return total / i; //返回平均值
}
3.下面是一个结构声明:
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
a。编写一个函数,按值传递box结构,并显示每个成员的值。
b。编写一个函数,传递box结构的地址,并将volume成员设置为其他三维长度的乘积。
c。编写一个使用这两个函数的简单程序。
答:
//结构地址 和 结构 作为函数参数时
#include<iostream>
using namespace std;
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
void volume(box*); //用于计算volume值
void show(box); //用于显示值
int main()
{
box player;
cout << "请输入名字: ";
cin.getline(player.maker, 39);
cout << "请输入高度: ";
cin >> player.height;
cout << "请输入宽度: ";
cin >> player.width;
cout << "请输入长度: ";
cin >> player.length;
volume(&player);
show(player);
system("pause");
return 0;
}
void volume(box*player)
{
player->volume = player->height*player->width*player->length; //是三个数的乘积
}
void show(box player)
{
cout << "名字: " << player.maker << endl;
cout << "高度: " << player.height << endl;
cout << "宽度: " << player.width << endl;
cout << "长度: " << player.length << endl;
cout << "体积: " << player.volume << endl;
}
4.许多州的彩票发行机构都使用如程序清单7.4所示的简单彩票玩法的变体。在这些玩法中,玩家从第一组被称为域号码(field number)的号码中选择几个。例如,可以从域号码1~47中选择5个号码;还可以从第二个区间(如1~27)选择一个号码(称为特选号码)。要赢得头奖,必须正确猜中所有的号码。中头奖的几率是选中所有域号码的几率与选中特选号码几率的乘积。例如,在这个例子中,中头奖的几率是从47个号码中正确选取5个号码的几率与从27个号码中正确选择1个号码的几率的乘积。请修改程序清单7.4,以计算中得这种彩票头奖的几率。
答:
备注:直接自己写个代码用来计算,不去看7.4了。
//计算彩票头奖中奖率
#include<iostream>
using namespace std;
long double field_number(int, int);
long double another(long double);
int main()
{
int x,y,m;
cout << "你要在x个号码中,选取y个数字,然后在m个号码中选取1个数字。\n假设要中头奖的话。你需要你选取的数字全部都是正确的。" << endl;
cout << "现在请设置x的值:";
cin >> x;
cout << "现在设置y的值:";
cin >> y;
cout << "现在设置m的值:";
cin >> m;
long double a_1 = field_number(x, y);
long double a_2 = another(m);
long double dajiang = a_1*a_2;
cout << endl;
cout.precision(20);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "你中大奖的几率是:" << dajiang*100 <<" %"<< endl;
system("pause");
return 0;
}
long double field_number(int max, int y)
{
long double total = 1;
for (int i = 0;i < y;i++)
total = total*(i + 1) / (max - i);
return total;
}
long double another(long double m)
{
long double x = 1 / m;
return x;
}
输出:
你要在x个号码中,选取y个数字,然后在m个号码中选取1个数字。
假设要中头奖的话。你需要你选取的数字全部都是正确的。
现在请设置x的值:47
现在设置y的值:5
现在设置m的值:27
你中大奖的几率是:0.00000241450520764105 %
请按任意键继续. . .
5.定义一个递归函数,接受一个整数参数,并返回该参数的阶乘。前面讲过,3的阶乘写作3!,等于3*2!,依次类推;而0!被定义为1。通用的计算公式是,如果n大于零,则n!=n*(n-1)!。在程序中对该函数进行测试,程序使用循环让用户输入不同的值,程序将报告这些值的阶乘。
答:
//阶乘的递归函数
#include<iostream>
using namespace std;
double jiecheng(double); //double防止数字过大而溢出
int main()
{
cout << "输入一个整数,程序将自动计算他的阶乘结果(负数或者其他字符退出):";
double m;
while (cin >> m)
{
cin.sync();
if (m < 0||!cin)break;
cout << m << "! = " << jiecheng(m) << endl;
cout << "请输入下一个数字(负数或者其他字符退出):";
}
cout << "Done." << endl;
system("pause");
return 0;
}
double jiecheng(double m)
{
double total = 1;
if (m == 0)return 1; //0的阶乘是1
if (m > 0) //大于1的时候,m-1的阶乘乘以m,当m=0时返回1。
{
total = jiecheng(m - 1)*m;
return total;
}
}
6.编写一个程序,它使用下列函数:
Fill_array()将一个double数组的名称和长度作为参数。它提示用户输入double值,并将这些值存储到数组中。当数组被填满或用户输入了非数字时,输入将停止,并返回实际输入了多少个数字。
Show_array()将一个double数组的名称和长度作为参数,并显示该数组的内容。
Reverse-array()将一个double数组的名称和长度作为参数,并将存储在数组中的值的顺序翻转。
程序将使用这些函数来填充数组,然后显示数组;反转数组,然后显示数组;反转数组中除第一个和最后一个元素之外的所有元素,然后显示数组。
答:
//填充、显示、反转数组
#include<iostream>
using namespace std;
const int a = 4; //初始定的数组数量
int Fill_array(double*, int); //填充数组函数
void Show_array(double*, int); //显示数组函数
void Reverse_array(double*, int); //反转数组
int main()
{
double m[a]; //声明数组m
int n = Fill_array(m, a); //输入,返回长度
Show_array(m, n); //显示
Reverse_array(m, n); //反转
Show_array(m, n); //显示
Reverse_array(m, n); //再反转
double x; //再把第一个和最后一个数调回来
x = m[0];
m[0] = m[n - 1];
m[n - 1] = x;
Show_array(m, n); //显示
system("pause");
return 0;
}
int Fill_array(double*m, int x)
{
cout << "你可以输入一个double数组,输入非数字时结束输入。最多可输入数字个数不超过 "<<x<<" 个。" << endl;
int i;
for (i = 0;i < x&&cin;i++, m++) //循环输入,输入非数字时结束
{
cout << i + 1 << "# : ";
cin >> *m;
}
if (!cin) //输入错误时,i已经+1了。所以需要-1
{
cin.clear();
i--;
}
cout << "你输入了 " << i << " 个数字。" << endl;
return i;
}
void Show_array(double*m, int n) //显示
{
for (int i = 0;i < n;i++,m++)
cout << i + 1 << "#数字: " << *m << endl;
cout << endl;
}
void Reverse_array(double*m, int n)
{
int i = 0;
double other;
for (i = 0;i < (n / 2);i++) //反转
{
other = m[i];
m[i] = m[n - i - 1];
m[n - i - 1] = other;
}
}
7.修改程序清单7.7的3个数组处理函数,使之使用两个指针参数来表示区间。fill_array()函数不返回实际读取了多少个数字,而是返回一个指针,该指针指向最后被填充的位置:其他函数可以将该指针作为第二个参数,以标识数据结尾。
答:
//填充、显示、标识数据结尾
#include <iostream>
using namespace std;
const int max = 5;
double*fill_array(double*, int); //填充
void show(double*, double*); //显示
void revalue(double*, double*, double); //改变
int main()
{
double m[max];
cout << "以下是给数组填充数字:" << endl;
double*x = fill_array(m, max); //填充,返回指针,指向最后一位有效数字
show(m, x); //m为开始,x为最后一位
if (x == (m - 1)) //如果没有输入有效数字
cout << "你没有输入有效数字,所以无法变换。" << endl;
else
{
cout << "请输入你要整体改变数组的倍数:" << endl;
double size;
cin >> size;
if (!cin) //错误或者小于0,不输出改变后的
{
cout << "输入错误,无法变换。" << endl;
cin.clear();
cin.sync();
}
else if (size < 0)
cout << "输入的是负数,无法变换。" << endl;
else
revalue(m, x, size); //改变时自带显示
}
system("pause");
return 0;
}
double*fill_array(double*m, int max) //输入函数
{
int i;
for (i = 0;i < max;i++)
{
cout << i + 1 << "# : ";
cin >> m[i];
if (!cin)
{
cin.clear();
cin.sync();
cout << "输入错误,输入结束..." << endl;
break;
}
else if(m[i]<0)
{
cout << "你输入了负数,输入结束..." << endl;
break;
}
}
double *a = &m[i-1]; //m[i-1]为数组有效位置的最后一位
return a;
}
void show(double*m, double*x) //显示函数
{
cout << endl << "这里将显示你输入的数字:" << endl;
while (m != (x+1))
{
int i = 0;
cout << ++i << "# = " << *m << endl;
m++;
}
}
void revalue(double*m, double*x,double a)
{
while (m != (x + 1))
{
int i = 0;
cout << ++i << "# = " << (*m *= a) << endl;
m++;
}
}
8.在不使用array类的情况下完成程序清单7.15所做的工作。编写两个这样的版本:
a。使用const char*数组存储表示季度名称的字符串,并使用double数组存储开支。
b。使用const char*数组存储表示季度名称的字符串,并使用一个结构,该结构只有一个成员——一个用于存储开支的double数组。这种设计与使用array类的基本设计相似。
答:
原程序的效果是:
创建double数组expenses,填充他(显示季节),显示他(每一季节和总体的和)。
//a。使用const char*数组存储表示季度名称的字符串,并使用double数组存储开支。
#include<iostream>
using namespace std;
const int seasons = 4;
void fill(double*, const char[][20]); //填充
void show(double*, const char[][20]); //显示
int main()
{
const char snames[seasons][20] = { "Spring","Summer","Fall","Winter" };
const char (*Snames)[20]=snames; //创建一个指针,指向一个20个字符的字符串数组。
double expenses[seasons]; //创建用于储存开支的数组
fill(expenses, Snames); //输入
show(expenses, Snames); //显示
system("pause");
return 0;
}
void fill(double*expenses, const char Snames[][20])
{
for (int i = 0;i < seasons;i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> expenses[i];
}
}
void show(double*expenses, const char Snames[][20])
{
double total = 0;
cout << "\n——————花费表——————\n";
for (int i = 0;i < seasons;i++)
{
cout << Snames[i] << " expenses: " << expenses[i] << endl;
total += expenses[i];
}
cout << "Total expenses: " << total << endl;
}
——————————————————————————————
//b。使用const char*数组存储表示季度名称的字符串,并使用一个结构,该结构只有一个成员——一个用于存储开支的double数组。这种设计与使用array类的基本设计相似。
#include<iostream>
using namespace std;
const int seasons = 4;
struct cost //注意:先声明结构,然后才能在下面的函数原型中调用
{
double expenses[seasons];
};
void fill(cost*, const char[][20]); //填充
void show(cost, const char[][20]); //显示
int main()
{
const char snames[seasons][20] = { "Spring","Summer","Fall","Winter" };
const char (*Snames)[20]=snames; //创建一个指针,指向一个20个字符的字符串数组。
cost Expenses;
fill(&Expenses, Snames); //输入
//注意,假如这里直接引入结构名的话,会提示未被初始化。
//原因在于函数使用的是结构的副本,而这里需要填充结构中的变量的内容
show(Expenses, Snames); //显示
system("pause");
return 0;
}
void fill(cost *Expenses, const char Snames[][20])
{
for (int i = 0;i < seasons;i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> Expenses->expenses[i];
}
}
void show(cost Expenses, const char Snames[][20])
{
double total = 0;
cout << "\n——————花费表——————\n";
for (int i = 0;i < seasons;i++)
{
cout << Snames[i] << " expenses: " << Expenses.expenses[i] << endl;
total += Expenses.expenses[i];
}
cout << "Total expenses: " << total << endl;
}
9.这个练习让您编写处理数组和结构的函数。下面是程序的框架,请提供其中描述的函数,以完成该程序。
#include<iostream>
using namespace std;
const int SLEN = 30;
struct student {
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
//getinfo() has two arguments: a pointer to the first element of
//an array of student structures and an int representing the
//number of elements of the array. The function solicits and
//stores data about students. It terminates input upon filling
//the array or upon encoutering a blank line for the student
//name. The function returns the actual number of array elements
//filled.
//翻译:getinfo()有2个参数,第一个指向student结构的数组中的第一个元素,另外一个参数是int类型,他表示是这个数组中的元素个数。这个函数请求和储存有关学生的数据。当遇见填满数组或者是遇见学生名字是一个空白行时终止输入。这个函数返回填充数组的元素数量
int getinfo(student pa[], int n);
//display1() takes a student structure as an argument
// and displays it contents
//翻译:display1()函数将学生结构名作为参数,并显示内容
void display1(student st);
//display2() takes the addres of student structure as an
// argument and displays the structure's contents
//翻译:display2()函数将学生结构的值作为参数,然后输出学生结构的内容
void display2(const student * ps);
//display3() takes the address of the first element of an array
// of student structures and the number of array elements as
// arguments and displays the contents of the structures
//display3()函数将结构数组的第一个元素的地址,以及数组的元素数量作为参数,然后输出这些结构的内容
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";
return 0;
}
答:
#include<iostream>
using namespace std;
const int SLEN = 30;
struct student {
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
//翻译:getinfo()有2个参数,第一个指向student结构的数组中的第一个元素,另外一个参数是int类型,他表示是这个数组中的元素个数。这个函数请求和储存有关学生的数据。当遇见填满数组或者是遇见学生名字是一个空白行时终止输入。这个函数返回填充数组的元素数量
int getinfo(student pa[], int n);
//翻译:display1()函数将学生结构名作为参数,并显示内容
void display1(student st);
//翻译:display2()函数将学生结构的值作为参数,然后输出学生结构的内容
void display2(const student * ps);
//display3()函数将结构数组的第一个元素的地址,以及数组的元素数量作为参数,然后输出这些结构的内容
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;
}
//翻译:getinfo()有2个参数,第一个指向student结构的数组中的第一个元素,另外一个参数是int类型,他表示是这个数组中的元素个数。这个函数请求和储存有关学生的数据。当遇见填满数组或者是遇见学生名字是一个空白行时终止输入。这个函数返回填充数组的元素数量
int getinfo(student pa[], int n)
{
int i=1;
while (i<n+1)
{
cout << "请输入" << i << "#学生的姓名:";
cin.getline(pa->fullname, 20);
if (pa->fullname[0] == ' ')
break;
cout << i << "#学生的爱好:";
cin >> pa->hobby;
cout << i << "#学生的opp水平(数字):";
cin >> pa->ooplevel;
cin.sync();
i++;
pa++;
cout << endl;
}
return (i - 1);
}
//翻译:display1()函数将学生结构名作为参数,并显示内容
void display1(student st)
{
cout << st.fullname << " 的爱好是: " << st.hobby << " 。他的OOP水平是:" << st.ooplevel << " 级。" << endl;
}
//翻译:display2()函数将学生结构的值作为参数,然后输出学生结构的内容
void display2(const student * ps)
{
cout << ps->fullname << " 的爱好是: " << ps->hobby << " 。他的OOP水平是:" << ps->ooplevel << " 级。" << endl;
}
//display3()函数将结构数组的第一个元素的地址,以及数组的元素数量作为参数,然后输出这些结构的内容
void display3(const student pa[], int n)
{
for (int i = 0;i < n;i++)
{
cout << i + 1 << "#学生的名字是: " << pa[i].fullname << endl;
cout << "爱好是: " << pa[i].hobby << endl;
cout << "oop水平是: " << pa[i].ooplevel << endl;
cout << endl;
}
}
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);
可以采用数组初始化语法,并将函数名作为地址来初始化这样的数组。
答:
//请编写一个程序,它调用上述两个函数和至少另一个与add()类似的函数。该程序使用循环来让用户成对地输入数字。对于每对数字,程序都使用calculate()来调用add()和至少一个其他的函数。
//注:创建一个指针数组,在main函数里根据不同情况调用这个指针数组的不同成员作为calculate函数的参数,
#include<iostream>
using namespace std;
double calculate(double, double,double(*)(double, double)); //calculate函数调用2个double值和一个函数指针,并将函数的返回值,作为calculate的返回值
//注,使用函数指针作为参数时,*需要被括号括起来
double add(double, double); //相加的函数
double jian(double, double); //相减的函数
int main()
{
double x, y;
cout << "请输入两个数字:" << endl;
double(*m[2]) (double, double) = { add,jian };//m是一个指向函数的指针数组
while (cin >> x >> y) //输入非要求的数时,结束循环
{
for (int i = 0;i < 2;i++)
{
if (i == 0)
{
cout << "两数的和为:" << calculate(x, y, *m[i]) << endl;
}
else
{
cout << "两数的差为:" << calculate(x, y, *m[i]) << endl;
}
}
cout << endl << "请输入两个数字:" << endl;
}
cout << "Done." << endl;
system("pause");
return 0;
}
double calculate(double x, double y, double(*com)(double, double))
{
double xx = com(x, y);
return xx;
}
double add(double x, double y)
{
return x+y;
}
double jian(double x, double y)
{
return x-y;
}
解释:
也可以在calculate函数内部进行选择,然后在函数内部进行指针变量判断——即相当于把for循环移动到了函数内部。
但是问题在于,calculate函数只能返回一个数。因此个人觉得这其实并不符合题意。
但就做法而言,是可行的。特别是假如calculate函数不需要返回值时(只有这样,才可以不用顾忌返回值问题),根据for循环,i不同时,函数指针指向不同的函数,然后调用函数指针和参数,执行函数。——但这样需要导入的指针是全局变量才可以(局部变量会被提示未初始化,除非你预先给他赋一个值/函数);