1.编译运行P3加练习
2.初识输入输出
C++语言未定义任何输入输出(IO)语句,取而代之,包含了一个全面的标准库(standard library)来提供IO机制。
iostream库包含两个基础类型istream和ostream,分别表示输入流和输出流。一个流就是一个字符序列,是从IO设备读出或写入IO设备的。术语“流”(stream)想要表达的是,随时间的推移,字符是顺序生成或消耗的。
标准输入输出 对象
istream类型的对象:
标准输入(standard input)cin(发音为see-in)
ostream类型的对象:
标准输出(standard output)cout(发音为see-out)
cout流在内存中对应开辟了一个缓冲区,用来存放流中的数据。当向cout流插人一个endl(并不等同于’\n’)时,不论缓冲区是否已满,都支即输出流中所有数据,然后插入一个换行符,并刷新流(清空缓冲区)。注意如果插入一个换行符,’\n’(如coot<<a<<’\n’;),则只输出a和换行,而不刷新cout流(但并不是所有编译系统都体现出这一区别)。
标准错误(standard error)cerr(发音为see-err)
cerr流已被指定为与显示器关联。cerr的作用是向标准出错设备(standard error device)输出有关出错信息。cerr是console error的缩写,意为“在控制台(显示器)显示出错信息”。cerr与标准输出流cout的作用和用法差不多。但有一点不同:cout流通常是传送到显示器输出,但也可以被重定向输出到磁盘文件,而cerr流中的信息只能在显示器输出。当调试程序时,往往不希望程序运行时的出错信息被送到其他文件,而要求在显示器上及时输出,这时应该用cerr。cerr流中的信息是用户根据需要指定的。
标准错误(standard error)clog(发音为see-log)
clog流对象也是标准出错流,它是console log的缩写。它的作用和cerr相同,都是在终端显示器上显示出错信息。它们之间只有一个微小的区别:cerr是不经过缓冲区,直接向显示器上输出有关信息,而clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出。
系统通常将程序所运行的窗口与这些对象关联起来,因此,当我们读取cin,数据将从程序正在运行的窗口读入,当我们向cout、cerr和clog写入数据时,将会写到同一个窗口。
endl这是个被称为操纵符(manipulator)的特殊值。写入endl的效果是结束当前行,并将与设备关联的缓冲区中的内容刷到设备中。缓冲刷新操作可以保证到目前为止程序所产生的所有输出都真正写入输出流中,而不是仅停留在内存中等待写入流(一般流的字符都会输出到屏幕,用endl是立即刷新输出。所以可以利用endl在调试的时候一直刷新流,出现程序崩溃的时候,输出没有及时输出)。
以下摘自
一、 C++ 输入输出的含义
以前所用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上。从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件。程序的输入指的是从输入文件将数据传送给程序,程序的输出指的是从程序将数据传送给输出文件。C++的输入与输出包括以下3方面的内容:
1、对系统指定的标准设备的输入和输出。简称标准I/O。(设备)。
2、以外存磁盘(或光盘)文件为对象进行输入和输出。简称文件I/0。(文件)。
3、对内存中指定的空间进行输入和输出。简称串I/O。(内存)。
二、 C++的I/O对C的发展—类型安全和可扩展性
1、C++的输入输出会对数据类型的合法性进行检查。
2、C++的I/O操作是可扩展的,不仅可以用来输入输出内置类型(built-in type)的数据,也可以用于用户自定义类型的数据。C++对标准类型的数据和对用户声明类型数据的输入输出,采用同样的方法处理。
三、 对流的解释
输入和输出是数据传送的过程,数据如流水一样从一处流向另一处。C++形象地将此过程称为流(stream)。C++的输入输出流是指由若干字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一对象。流表示了信息从源到目的端的流动。在输入操作时,字节流从输入设备(如键盘、磁盘)流向内存,在输出操作时,字节流从内存流向输出设备(如屏幕、打印机、磁盘等)。流中的内容可以是ASCII字符、二进制形式的数据、图形图像、数字音频视频或其他形式的信息。
实际上,在内存中为每一个数据流开辟一个内存缓冲区,用来存放流中的数据。当用cout和插入运算符“<<”向显示器输出数据时,先将这些数据送到程序中的输出缓冲区保存,直到缓冲区满了或遇到endl,就将缓冲区中的全部数据送到显示器显示出来。在输入时,从键盘输入的数据先放在键盘缓冲区中,当按回车键时,键盘缓冲区中的数据输入到程序中的输入缓冲区,形成cin流,然后用提取运算符“>>”从输入缓冲区中提取数据送给程序中的有关变量。总之,流是与内存缓冲区相对应的,或者说,缓冲区中的数据就是流。
在C++中,输入输出流被定义为类。C++的I/0库中的类称为流类(streamclass)。用流类定义的对象称为流对象。
前面曾多次说明,cout和cin并不是C++语言中提供的语句,它们是iostream类的对象,在未学习类和对象时,在不致引起误解的前提下,为叙述方便,把它们称为cout语句和cin语句。正如C++并未提供赋值语句,只提供赋值表达式,在赋值表达式后面加分号就成了C++的语句,为方便起见,我们习惯称之为赋值语句。又如,在C语言中常用printf和scanf进行输出和输入,printf和scanf是C语言库函数中的输入输出函数,一般也习惯地将由printf和scanf函数构成的语句称为printf语句和scanf语句。在使用它们时,对其本来的概念要有准确的理解。
3.读取数量不定的输入数据
#include<iostream>
int main()
{
using std::cout;
int sum = 0, value = 0;
while (std::cin >> value)
{
sum += value;
}
cout << "Sum is:" << sum << std::endl;
return 0;
}
当我们使用一个istream对象作为条件时,其效果是检测流的状态。如果流是有效的,即流未遇到错误,那么检测成功。当遇到文件结束符,或遇到一个无效输入时(例如读入的值不是一个整数),istream对象的状态会变为无效。处于无效状态的istream对象会使条件变为假。
当从键盘向程序输入数据时,对于如何指出文件结束,不同操作系统有不同的约定。在windows系统中,输入文件结束符的方法是敲Ctrl+Z,然后按Enter或Return键。
例程:
#include<iostream>
#include<string>
class Sales_item {
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool operator==(const Sales_item&, const Sales_item&);
public:
#if defined(IN_CLASS_INITS)&&defined(DEFAULT_FCNS)
Sales_item() = default;
#else
Sales_item() :units_sold(0), revenue(0.0) {}
#endif
Sales_item(const std::string &book) :bookNo(book), units_sold(0), revenue(0.0) {}
Sales_item(std::istream&is) { is >> *this; }
public:
Sales_item&operator+=(const Sales_item&);
std::string isbn()const { return bookNo; }
double avg_price()const;
private:
std::string bookNo;
#ifdef IN_CLASS_INITS
unsigned units_sold = 0;
double revenue = 0.0;
#else
unsigned units_sold;
double revenue;
#endif
};
inline bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool operator==(const Sales_item&lhs, const Sales_item&rhs)
{
// must be made a friend of Sales_item
//要访问私有成员必须声明为友元函数
return lhs.units_sold == rhs.units_sold&&
lhs.revenue == rhs.revenue&&
lhs.isbn() == rhs.isbn();
}
inline bool operator !=(const Sales_item&lhs, const Sales_item&rhs)
{
return !(lhs == rhs);
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
/*
*实践证明, 类(class)私有成员可以被类成员函数访问, 不区分成员在哪个实例(instance)里。
*也就是说,在类内部的成员函数中,哪怕是传入的对象,也是可以直接访问该对象的私有成员。
*(前提是该对象必须是本类型的一个对象)
*/
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item operator+(const Sales_item&lhs, const Sales_item&rhs)
{
Sales_item ret(lhs);
ret += rhs;
return ret;
}
std::istream& operator>>(std::istream&in, Sales_item&s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold*price;
else
s = Sales_item();
return in;
}
std::ostream& operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
int main()
{
freopen("input.txt", "rb", stdin);
Sales_item total;
if (std::cin >> total)
{
Sales_item trans;
while (std::cin >> trans)
{
if (total.isbn() == trans.isbn())
{
total += trans;
}
else
{
std::cout << total << std::endl;
total = trans;
}
}
std::cout << total << std::endl;
}
else
{
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
}
输入
0-201-70353-X 4 24.99
0-201-82470-1 4 45.39
0-201-88954-4 2 15.00
0-201-88954-4 5 12.00
0-201-88954-4 7 12.00
0-201-88954-4 2 12.00
0-399-82477-1 2 45.39
0-399-82477-1 3 45.39
0-201-78345-X 3 20.00
0-201-78345-X 2 25.00
4.基本内置类型 P(30)
基本内置类型包括:算术类型(arithmetic type)和空类型(void)
- 算术类型:整型(包括字符和布尔类型在内)和浮点型
类型 | 含义 | 最小尺寸 |
---|---|---|
bool | 布尔类型 | 未定义 |
char | 字符 | 8位 |
wchar_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整型 | 16位 |
long | 长整型 | 32位 |
long long | 长整型 | 64位 |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
基本的字符类型是char,一个char的空间应确保可以存放机器基本字符集中任意字符对应的数字值。也就是说,一个char的大小和一个机器字节一样。
其他字符类型用于扩展字符集,如wchar_t、char16_r、char32_t。
除了字符和布尔类型至外,其他类型用于表示(可能)不同尺寸的整数。C++语言规定一个int至少和一个short一样大,一个long至少和一个int一样大,一个longlong至少和一个long一样大。其中,数据类型longlong是在C++11中新定义的。
通常,float以1个字(32比特)来表示,double以2个字(64比特)来表示,long double以3或4个字(96或128比特)来表示。执行浮点数运算选用double,这是因为float通常精度不够而且双精度浮点和单精度浮点数的计算代价相差无几。对于某些机器来说,双精度运算甚至比单精度还快。
除去布尔型和扩展的字符型之外,其他整型可以划分为带符号的(signed)和无符号的(unsigned)两种。
与其他整型不同字符型被分为了三种:char、signed char和unsigned char。char和类型signed char并不一样。尽管字符型有三种,但是字符的表现形式却只有两种:带符号的和无符号的。类型char实际上会表现为上述两种形式中的一种,具体是哪种由编译器决定。