《C++ Primer Plus第6版中文版》学习笔记(第一 ~第六章)
http://download.csdn.net/detail/qq20004604/9359697
《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不同时,函数指针指向不同的函数,然后调用函数指针和参数,执行函数。——但这样需要导入的指针是全局变量才可以(局部变量会被提示未初始化,除非你预先给他赋一个值/函数);