习题选自:C++ Primer Plus(第六版)
内容仅供参考,如有错误,欢迎指正 !
1.简单文件输入/输出(写入到文本文件中)
对于文件输入,C++使用类似于cout的东西。对于cout,需要包含iostream头文件,该头文件定义了一个用于输出的ostream类,并且在该头文件中声明了一个cout的ostream变量(对象)。而在使用到文本写入文件时,需要包含头文件fstream,该头文件定义了一个ofstream类,使用的时候需要声明一个ofstream类,声明完成后需要通过open()方法将声明的对象与文件关联起来,例如:
ofstream outFile;
outFile.open("filename.txt");
然后就可以像使用cout一样使用该ofstream对象。将在屏幕上打印的数据信息,存储到文件中去。最后使用close()方法将其关闭。
cout<<fixed
与outFile<<fixed
用一般的方式输出浮点型,例如C++程序在控制台显示大一点的数,显示的时候使用了科学计数法,使用该命令即可像一般的方式显示。cout.precision(2)
与outFile.precision(2)
设置精确度为2,并返回上一次的设置。cout.setf(iOS_base::showpoint)
与outFile.setf(iOS_base::showpoint)
显示浮点数小数点后面的零。2.简单文件输入/输出(读取文本文件)
对于文件读取,同样的,C++使用类似cin的东西。对于cin,需要包含iostream头文件,该文件定义了一个用于输入的istream类,并在该头文件中已经声明好了一个cin的istream变量(对象)。而在使用读取文件时,需要包含fstream头文件,该头文件定义了ifostream类,在使用的时候需要声明一个ifstream类,通过open()方法与文件关联起来,然后就可以像使用cin一样使用该ifstream,读取目标文件的内容。最后,使用close()方法将文件关闭。
- 可以结合ifstream对象和运算符>>来读取各种类型的数据。
- 可以使用ifstream对象与get()方法读取一个字符,使用getline()来读取一行字符。
- 可以结合使用ifstream与eof()、fail()等方法判断输入是否成功。
复习题
1 .请看下面两个计算空格和换行符数目的代码片段:
//version 1
while(cin.get(ch)) //quit on eof
{
if(ch==' ')
spaces++;
if(ch=='\n')
newlines++;
}
//version 2
while(cin.get(ch)) //quit eof
{
if(ch==' ')
spacees++;
else if(ch=='\n')
newlines++;
}
第二个格式比第一个格式好在哪里?
第二个版本比第一个版本效率更高,因为在第一个中对于每个字符都需要判断两次,而在第二个版本中,如果字符为空格,在经过if判断确定为空格后,该字符肯定不是换行符,第二个else if的判断直接跳过,节省判断时间。
2.在程序清单6.2中,用ch+1替换++ch将发生什么情况?
程序清单6.2 ifelse.cpp
// ifelse.cpp -- using the if else statement #include <iostream> int main() { char ch; std::cout << "Type, and I shall repeat.\n"; std::cin.get(ch); while (ch != '.') { if (ch == '\n') std::cout << ch; // done if newline else std::cout << ++ch; // done otherwise std::cin.get(ch); } // try ch + 1 instead of ++ch for interesting effect std::cout << "\nPlease excuse the slight confusion.\n"; // std::cin.get(); // std::cin.get(); return 0; }
++ch的数据类型依旧是char型,但对于char+1最终类型为int型,因此当++ch换成ch+1后,输出的是数字。
3.请认真考虑下面的程序:
#include<iostream>
using namespace std;
int main()
{
char ch;
int ct1,ct2;
ct1=ct2=0;
while((ch=cin.get())!='$')
{
cout<<ch;
ct1++;
if(ch='$')
ct2++;
cout<<ch;
}
cout<<"ct1="<<ct1<<",ct2="<<ct2<<"\n";
return 0;
}
假设输入如下(请在每行末尾按回车键):
Hi!
Send $10 or $20 now!
则输出将是什么(还记得吗,输入被缓冲)?
输入输出结果为
Hi!
H$i$!$
$Send $10 or $20 now!
S$e$n$d$ $ct1=9,ct2=9
由于程序中使用的是ch='$'
,所以每次循环该if条件内代码都执行一次,因此ct1与ct2相等。同时在输入Hi!
之后键入回车,因此在读取回车之后,打印出来,光标换行,紧接着打印$。
4.创建表示下述条件的逻辑表达式:
a.weight大于或等于115,但小于125。
b.ch为q或Q。
c.x为偶数,但不是26.
d.x为偶数,但不是26。
e.donation为1000-2000或guest为1。
f.ch是小写字母或大写字母(假设小写字母是依次编码的,大写字母也是依次编码的,但在大小写字母间编码是不连续的)。
//a
weight>=115 && weight<125
//b
ch=='q' || ch=='Q'
//c
x%2==0 && x!=26
//d
x%2==0 && x%26!=0
//e
donation>=1000 && donation<=20000 || guest==1
//f
(ch>='a' && ch<='z') || (ch<='Z' && ch>='A')
5.在英语中,"I will not not speak(我不会不说) "的意思与"I will speak(我要说)"相同。在c++中,!!x是否与x相同呢?
对于bool变量而言,!!x与x是相同的,但对于其他类型变量不一定相同,例如!!5=1,!!5≠5。
6.创建一个条件表达式,其值为变量的绝对值。也就是说,如果变量x为正,则表达式的值为x;但如果x为负,则表达式的值为-x–这是一个正值。
x>=0 ? x : -x;
7.用switch改写下面的代码片段:
if(ch=='A')
a_grade++;
else if(ch=='B')
b_grade++;
else if(ch=='C')
c_grade++;
else if(ch=='D')
d_grade++;
else
f_grade++;
改写后代码:
switch(ch)
{
case 'A' : a_grade++;
break;
case 'B' : b_grade++;
break;
case 'C' : c_grade++;
break;
case 'D' : d_grade++;
break;
default : f_grade++;
break;
}
8.对于程序清单6.10,与使用字符(如a和c)表示菜单选项和case标签有何优点呢?(提示:想一想用户输入q和输入5的情况。)
程序清单6.10 switch.cpp
// switch.cpp -- using the switch statement #include <iostream> using namespace std; void showmenu(); // function prototypes void report(); void comfort(); int main() { showmenu(); int choice; cin >> choice; while (choice != 5) { switch (choice) { case 1: cout << "\a\n"; break; case 2: report(); break; case 3: cout << "The boss was in all day.\n"; break; case 4: comfort(); break; default: cout << "That's not a choice.\n"; } showmenu(); cin >> choice; } cout << "Bye!\n"; return 0; } void showmenu() { cout << "Please enter 1, 2, 3, 4, or 5:\n" "1) alarm 2) report\n" "3) alibi 4) comfort\n" "5) quit\n"; } void report() { cout << "It's been an excellent week for business.\n" "Sales are up 120%. Expenses are down 35%.\n"; } void comfort() { cout << "Your employees think you are the finest CEO\n" "in the industry. The board of directors think\n" "you are the finest CEO in the industry.\n"; }
使用数字作为菜单选项和case标签,限定了用户只有输入数字的时候才能有效,若用户错误的输入非整数类型,导致程序被挂起。而使用字符作为菜单选项和case标签,当用户输入错误类型,程序能正确通过default部分提示用户输入错误,用户体验更加友好,提高了程序的容错性和健壮性。
9.请看下面的代码片段
int line = 0;
char ch;
while(cin.get(ch))
{
if(ch=='Q')
break;
if(ch!='\n')
continue;
line++;
}
重写后代码:
int line = 0;
char ch;
while(cin.get(ch) && ch!='Q')
{
if(ch=='\n')
line++;
}
编程练习
1.编写一个程序,读取键盘输入,直到遇到@符号为止,并回显输入(数字除外),同时将大写字符转换为小写字符,将小写字符转换为大写(别忘了cctype函数系列)
#include<iostream>
#include<cctype>
using namespace std;
int main()
{
cout << "Please enter characters (type @ to stop):";
char ch;
cin.get(ch);
while (ch != '@')
{
if (islower(ch))
ch = toupper(ch);
else if (isupper(ch))
ch = tolower(ch);
if (!isdigit(ch))
cout << ch;
cin.get(ch);
}
system("pause");
return 0;
}
2.编写一个程序,最多将10个donation值读入一个double数组中(如果你愿意,也可以使用模板类array)。程序遇到非数字输入时将结束输入,并报告这些数字的平均值以及数组中有多少个数字大于平均值。
#include<iostream>
#include<array>
using namespace std;
int main()
{
array<double,10>donations;
double sum=0;
cout<<"Please enter donation(non-number to stop):";
int i;
double donation;
for(i=0;(i<10)&&(cin>>donation);++i)
{
donations[i]=donation;
sum=+donations[i];
}
double avg=sum/(i+1);
cout<<"Average:"<<avg<<endl;
cout<<"Number larger than average:";
for(int j=0;j<i;j++)
{
if(donations[j]>avg)
cout<<donations[j]<<" ";
}
cout<<endl;
return 0;
}
3.编写一个菜单驱动程序的雏形。该程序显示一个提供四个选项的菜单–每个选项用一个字母表标记。如果用户使用有效选项之外的字母进行响应,程序将提示用户输入有效的字母,直到用户这样选择为止。然后,该程序使用一条switch语句,根据用户的选择执行一个简单操作。该程序的运行情况如下:
Please enter one of the following choices:
c) carnivore p) pianist
t) tree g)game
f
Please enter a c,p,t or g:q
Please enter a c,p,t or g:t
A maple is a tree.
代码实现:
#include <iostream>
using namespace std;
int main()
{
cout<<"Please enter one of the following choices:"<<endl;
cout<<"c) carnivore p) pianist"<<endl;
cout<<"t) tree g) game"<<endl;
char ch;
cin>>ch;
while(ch!='c' && ch!='p' && ch!='t' && ch!='g')
{
cout<<"Please enter a c,p,t or g:";
cin>>ch;
}
switch (ch)
{
case 'c':
cout<<"A maple is a carnivore."<<endl;
break;
case 'p':
cout<<"A maple is a pianist."<<endl;
break;
case 't':
cout<<"A maple is a tree."<<endl;
break;
case 'g':
cout<<"A maple is a game."<<endl;
break;
default:
break;
}
return 0;
}
4.加入Benevolent Order of Programmer后,在BOP大会上,人们便可以通过加入者的真实姓名、头衔或秘密BOP姓名来了解他(她)。请编写一个程序,可以使用真实姓名、头衔、秘密姓名或成员偏好来列出成员。编写该程序时,请使用下面的结构:
//Benevolent Order of Programmers name structure
struct bop{
char fullname[strsize]; //real name
char title[strzie]; //job title
char bopname[strsize]; //secret BOP name
int preference; //0=fullname,1=title,2=bopname
};
该程序创建一个由上述结构组成的小型数组,并将其初始化为适当的值。另外,该程序使用一个循环,让用户在下面的选项中进行选择:
a.display by name b.diaplay by title
c.display by bopname d.display by preference
q.quit
注意,“display by preference”并不意味显示成员的偏好,而是意味着根据成员的偏好来列出成员。例如,如果偏好号为1,则选择d将显示程序员的头衔。该程序的运行情况如下:
Benevolent Order of Programmers Report
a. display by name b. display by title
c. display by bopname d. display by preference
q. quit
Enter your choice: a
Wimp Macho
Raki Rhodes
Celia Laiter
Hoppy Hipman
Pat Hand
Next choice: d
Wimp Macho
Junior Programmer
MIPS
Analyst Trainee
LOOPY
Next choice: q
Bye!
代码实现 :
#include <iostream>
using namespace std;
const int strsize = 20;
struct bop
{
char fullname[strsize];
char title[strsize];
char bopname[strsize];
int preference; //0 = fullname, 1 = title, 2 = bopname
};
int main()
{
int programmerNum = 5;
bop programmers[programmerNum]={{"Wimp Macho", "Junior Programmer", "WM",0},
{"Raki Rhodes", "Junior Programmer", "RR", 1},
{"Celia Laiter", "Junior Programmer", "MIPS", 2},
{"Hoppy Hipman", "Analyst Trainee", "HH", 1},
{"Pat Hand", "Junior Programmer", "LOOPY", 2}};
cout << "Benevolent Order of Programmers Report" << endl;
cout << "a. display by name b. display by title" << endl;
cout << "c. display by bopname d. display by preference" << endl;
cout << "q. quit" << endl;
cout << "Enter your choice: ";
char choice;
while(cin.get(choice))
{
if(choice == 'a')
{
for(int i = 0; i < programmerNum; i++)
{
cout << programmers[i].fullname << endl;
}
}
else if(choice == 'b')
{
for(int i = 0; i < programmerNum; i++)
{
cout << programmers[i].title << endl;
}
}
else if(choice == 'c')
{
for(int i = 0; i < programmerNum; i++)
{
cout << programmers[i].bopname << endl;
}
}
else if(choice == 'd')
{
for(int i = 0; i < programmerNum; i++)
{
if(programmers[i].preference == 0)
{
cout << programmers[i].fullname << endl;
}
else if(programmers[i].preference == 1)
{
cout << programmers[i].title << endl;
}
else
{
cout << programmers[i].bopname << endl;
}
}
}
else if(choice == 'q')
{
cout << "Bye!" << endl;
break;
}
else
{
if(choice == '\n')
{
continue;
}
cout << "input error, please re-enter!" << endl;
}
cout << "Next choice: ";
}
return 0;
}
5.在Neutronia王国,货币单位是tvarp,收入所得税的计算方式如下:
5000 tvarps: 不收税
5001~15000 tvarps: 10%
15001~35000 tvarps: 15%
35000 tvarps以上: 20%
例如,收入为38000 tvarps时,所得税为5000×0.00+10000×0.10+2000×0.15+3000×0.20,即 4600tvarps。请编写一个程序,使用循环来要求用户输入收入,并报告所得税,当用户输入负数或非数字时,循环将结束。
代码实现:
#include<iostream>
using namespace std;
int main()
{
cout << "Please enter your income(if you enter negative number or non-numberic, it will exit.) : ";
double income, tax;
while(cin >> income)
{
cout<< income <<endl;
if(income > 35000)
{
tax = 10000 * 0.10 + 20000 * 0.15 + (income - 35000) * 0.20;
}
else if(income >= 15001)
{
tax = (income - 3500) * 0.15 +10000 * 0.10;
}
else if(income >= 5001)
{
tax = (income - 5000) * 0.10;
}
else if(income >= 0)
{
tax = 0;
}
else
{
cout << "Enter negative number, exiting soon..." << endl;
break;
}
cout << "your should pay tax : " << tax << " tvarps." << endl;
cout << "Please enter another income(if you enter negative number or non-numberic, it will exit.) : ";
}
cout << "Exited, Bye !" << endl;
return 0;
}
6.编写一个程序,记录捐助给"维护合法权利团体"的资金。该程序要求用户输入捐赠者数目,然后要求用户输入每一个捐献者的姓名和款项。这些信息被存储在一个动态分配的结构数组中.每个数据结构有两个成员:用来存储姓名的字符串数组(或string对象)和用来存储款项的double成员。读取所有的数据后,程序将显示所有捐款超过10000的捐款着姓名及其捐款数额。该列表前应包含一个标题,指出下面的捐款者是重要捐款人(Grand Patrons)。然后,程序将列出其他的捐款者,该列表要以Partons开头。如果某种类别没有捐款者,则程序将打印单词"none"。该程序只显示这两种类别,而不进行排序。
代码实现:
#include<iostream>
#include<string>
using namespace std;
struct DonationInfo{
string name;
double amount;
};
void donationInfoDisplay(DonationInfo donationInfo[], int num, bool isGrandPatrons)
{
int countNum = 0;
for(int i = 0 ; i < num ; i++)
{
if(isGrandPatrons)
{
if(donationInfo[i].amount > 10000)
{
countNum++;
cout << donationInfo[i].name << endl;
}
}
else
{
if(donationInfo[i].amount <= 10000)
{
countNum++;
cout << donationInfo[i].name << endl;
}
}
}
if(countNum == 0)
cout << "none" << endl;
}
int main()
{
cout << "Please enter the number of donors :";
int num;
while(!(cin >> num))
{
cin.clear();
cin.sync();
cin.ignore();
cout << "***[WARNING]:Please enter positive integer.***" << endl;
cout << "Please enter the number of donors :";
}
DonationInfo* donationInfo = new DonationInfo[num];
for(int i = 0; i < num; i++)
{
cout << "enter the donor name :";
cin >> donationInfo[i].name;
cout << "enter the donation amount :";
cin >> donationInfo[i].amount;
}
cout << "******Grand Partons******" << endl;
donationInfoDisplay(donationInfo, num, true);
cout << "******Partons******" << endl;
donationInfoDisplay(donationInfo, num, false);
delete[] donationInfo;
return 0;
}
7.编写一个程序,它每次读取一个单词,直到用户只输入q。然后,该程序指出有多少个单词以元音打头,有多少个单词以辅音打头,还有多少个单词不属于这两类。为此,方法之一是,使用isalpha()来区分以字母和其他字母打头的单词,然后对于通过isalpha()测试的单词,使用if或switch语句来确定哪些以元音打头。该程序的运行情况如下:
Enter words (q to quit):
The 12 awesome oxem ambled
quiety across 15 meters of lawn. q
5 words beginning with vowels
4 words beginning with consonants
2 others
代码实现:
#include<iostream>
#include<string>
using namespace std;
int main()
{
cout << "Enter words (q to quit) :" << endl;
string word;
int vowelNum = 0;
int consonantNum = 0;
int othersNum = 0;
while(cin >> word)
{
if(word == "q")
{
break;
}
else
{
if(isalpha(word[0]))
{
switch(word[0])
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
vowelNum++;
break;
default:
consonantNum++;
}
}
else
{
othersNum++;
}
}
}
cout << vowelNum << " words beginning with vowels" << endl;
cout << consonantNum << " words beginning with consonants" << endl;
cout << othersNum << " others" <<endl;
return 0;
}
8.编写一个程序,他打开一个文件,逐个字地读取该文件,直到到达文件末尾,然后指出该文件中包含多少个字符。
代码实现:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
ifstream txtSource;
txtSource.open("test.txt", ios::in);
if(!txtSource.is_open())
{
cout << "File failed to open !" << endl;
exit(EXIT_FAILURE);
}
char ch;
int characterNum = 0;
while(txtSource >> ch)
{
characterNum++;
}
if (txtSource.eof())
cout << "End of file reached.\n";
else if (txtSource.fail())
cout << "Input terminated by data mismatch." << endl;
else
cout << "Input terminated for unknown reason." << endl;
if(characterNum == 0)
cout << "No data processed." << endl;
else
cout << "The file contains " << characterNum << " characters" << endl;
txtSource.close();
return 0;
}
9.完成编程练习6,但从文件中读取所需的信息。该文件的第一项应为捐款人数,余下的内容应为对的行。在每一对中,第一行为捐款人姓名,第二行为捐款数额。即该文件类似于下面:
代码实现:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
struct DonationInfo{
string name;
double amount;
};
void donationInfoDisplay(DonationInfo donationInfo[], int num, bool isGrandPatrons)
{
int countNum = 0;
for(int i = 0 ; i < num ; i++)
{
if(isGrandPatrons)
{
if(donationInfo[i].amount > 10000)
{
countNum++;
cout << donationInfo[i].name << endl;
}
}
else
{
if(donationInfo[i].amount <= 10000)
{
countNum++;
cout << donationInfo[i].name << endl;
}
}
}
if(countNum == 0)
cout << "none" << endl;
}
int main()
{
cout << "Read file content..." << endl;
ifstream txtDonationInfo;
txtDonationInfo.open("test.txt", ios::in);
if(!txtDonationInfo.is_open())
{
cout << "File failed to open !" << endl;
exit(EXIT_FAILURE);
}
int num = 0;
(txtDonationInfo >> num).get();
DonationInfo* donationInfo = new DonationInfo[num];
for(int i = 0; i < num; i++)
{
txtDonationInfo >> donationInfo[i].name;
txtDonationInfo >> donationInfo[i].amount;
}
cout << "******Grand Partons******" << endl;
donationInfoDisplay(donationInfo, num, true);
cout << "******Partons******" << endl;
donationInfoDisplay(donationInfo, num, false);
delete[] donationInfo;
txtDonationInfo.close();
return 0;
}