1. 数据类型
C++中的常见数据类型包括int
, long long
, float
, double
, char
, string
, bool
。其中int
(32位)和long long
(64位)表示整型,float
(32位)和double
(64位)表示浮点型;char
表示字符,用单引号表示,一对单引号中有且仅有一个字符,空格也是一个字符,转义字符在书写上表达为多个字符,但是实际上表示单个字符;string
表示字符串,用双引号表示;bool
表示布尔类型,其值只能设置为true
或false
,也可以用1或0代替。
#include<stdio.h>
int main()
{
int a=67;
float b=2.578;
char c='a';
printf("a=%d\n",a);
printf("b=%.2f\n",b);
printf("c=%c\n",c);
return 0;
}
a=67b=2.58
c=a
- 第4-6行中的=表示赋值,将右侧计算的结果赋值给左侧的变量。注意赋值号左边只能写一个变量,不能对多个变量同时赋值。
第7-9行中的\n表示输出一个新行。C++中以\开头的字符称为转义字符,表示特殊含义。例如\t表示制表符, \n表示回车符。 | 转义字符 | 意义 | 转义字符 | 意义 | | —- | —- | —- | —- | | \n | 换行(LF) ,将当前位置移到下一行开头 | \‘ | 代表一个单引号(撇号)字符 | | \r | 回车(CR) ,将当前位置移到本行开头 | \“ | 代表一个双引号字符 | | \t | 水平制表(HT) (跳到下一个TAB位置) | \? | 代表一个问号 | | \\ | 代表一个反斜线字符’’\‘ | \0 | 空字符(NULL) |
a
,b
,c
被称为变量,它和函数名等其他自定义符合统称为标识符。标识符可以由字母、数字和 (下划线)组合而成,变量名必须以字母或 (下划线)开头。标识符是大小写敏感的,即区分大小写,a
和A
是两个不同的变量。以下都是合法的数据类型和标识符,建议使用有意义的名字作为变量名,在程序阅读时,通过变量名就可以理解程序的含义。int myNum = 5; // Integer (whole number)
float myFloatNum = 5.99; // Floating point number
double myDoubleNum = 9.987868; // Floating point number
char myLetter = 'D'; // Character
bool myBoolean = true; // Boolean
string myText = "Hello"; // String
代码2.1中的
printf
是C语言的屏幕输出方式,其中的%d
,%.2f
和%c
称为占位符,分别表示整型、浮点型和字符类型,对应变量(a
,b
,c
)的值将在占位符位置进行输出。其中%.2f表示输出的浮点数精度保留两位小数,如果是double
类型,采用%.2lf
的形式。printf
书写比较复杂,还要进行类型控制,在C++中不推荐使用,C++的cout
形式输出更加常用。cout
能够自动进行类型检测,不需要书写占位符,使用更加简单方便。如果涉及精度控制等特殊要求,可以采用printf
形式。#include <iostream>
using namespace std;
int main()
{
cout << "我喜欢中国石油大学(华东)" << endl;
int a,b,c;
double d,e,f;
char g;
cout << "a = " << a << " b = " << b << " c = " << c << endl;
cout << "d = " << d << " e = " << e << " f = " << f << endl;
cout << "g = " << g << endl;
}
我喜欢中国石油大学(华东)a = 4354478 b = 7208832 c = 4354384
d = 1.33485e-306 e = -1.41601e+143 f = 1.33501e-306
g =
运行以上代码,结果可能跟以上结果不相同。这里实际上包含了一条重要的原则,变量在使用前必须初始化。因此以上程序在运行时会出现7个警告,例如:’a’ is used uninitialized in this function。当一个变量进行定义后,会根据指定的数据类型分配内存空间。但是由于未初始化,对应内存空间内的数值不会发生任何改变,把该内存空间中的二进制数值按照变量的数据类型进行解析,因此对应变量的值可以认为是任意值。这是非常危险的操作,它可能导致代码在本地运行结果正确,但是提交到服务器上进行在线评测的时候就发生了错误。2. 整型
2.1 整型的数值范围
以
int
类型为例,分析一下整型数据类型的内存表示。int
由连续的4字节构成,共32比特,它在内存中的分配如图2.1所示。最高位作为符号位,剩余31位,因此int
类型的数值范围为-231~231-1,最大值减一是因为0要占一种表示方式。如果最高位不作为符号位,即unsigned int
类型,数值范围转换为0~232-1。
图2.1 int类型的内存分配
与之类似,long long
为64位的整型,char是8位的整型。表2.1列举了<climits>
头文件中定义的部分常量,从这些常量中可以看到char
,int
,long long
数据类型的表示范围。
表2.1 climits头文件中定义的部分常量
名称 | 用途 | 值 | 名称 | 用途 | 值 |
---|---|---|---|---|---|
CHAR_ BIT | char类型比特数 | 8 | CHAR_ MAX | char类型最大值 | +27-1 |
CHAR_ MIN | char类型最小值 | -27 | UCHAR_ MAX | unsigned char 类型最大值 | +28-1 |
INT_ MAX | int类型最大值 | +231-1 | INT_ MIN | int类型最小值 | -231 |
UINT_ MAX | unsigned int 类型最大值 | +232-1 | LLONG_ MAX | long long 类型最大值 | +263-1 |
LLONG_ MIN | long long类型最小值 | -263 | ULLONG_ MAX | unsigned long long 类型最大值 | +264-1 |
因为每种类型都有其存储范围,如果数值过大,保留不了,高位多出的部分就会被自动忽略,结果就会发生错误。这种现象被称为内存溢出。因此在程序设计时,一定要确保对应的数据类型能够保证所有的可能值能被正确的存储。
在线评测网站上的题目经常出现数值范围为-109~109或-1018~1018等类似的数值范围说明。可以通过估算法确定采用何种数据类型。这种方法在线评测的时候经常会用得到。
估算法:因为210=1024约等于103,也就是说每10位二进制就可以表示3位十进制。因此int可以保留109以下的精度,long long可以保留1018以下的精度。
2.2 整数十进制转换为二进制
整数十进制转换为二进制采用的经典方法称为除2取余法。具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为0停止。最后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来,就得到了对应的二进制。
图2.2 整数150转换为二进制10010110
3. 浮点类型
3.1 浮点数的内存表示
浮点数就是所谓的小数,一个float类型的对象占据4个字节共32比特。这32个比特以类似于科学计
数法的形式来表达一个浮点数,按照IEEE 754标准,如图2.3所示,最高的1位(第31位)用做符号位,接着的8位(第23-30位)是指数E,剩下的23位(第0-22位)为有效数字M。按照这样的表示方法,浮点数的表示精度是有限的。double类型为64位,它的表示精度更大,但毕竟也是有限的。
图2.3 float类型的内存表示
3.2 纯小数十进制转换为二进制
纯小数十进制转换为二进制采用的经典方法称为乘2取整法。具体做法是:用2乘十进制小数,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,或者达到所要求的精度为止。最后把先得到的余数作为二进制数的高位有效位,后得到的余数作为二进制数的低位有效位,依次排列起来,就得到了对应的二进制。连接为二进制的时候从上往下,这与除2取整法是相反的。
图2.4 纯小数0.6875转换为二进制0.1011
可以尝试用该方法转换其他纯小数,就会发现除了2-n或多个2-n之和外,其他数值转换为二进制小数时都是无限的,而每个浮点数在计算机中的表示一定是有精度限制的。由此可以得到结论,绝大部分十进制小数在计算机中都是无法精确存储的。
由此,在程序设计中存在一个奇异的特性,浮点数无法精确比较。
#include <iostream>
using namespace std;
int main()
{
float a=0.9876;
int b = 9876;
cout<<(a==0.9876)<<endl; //错误浮点数比较方式
cout<<(fabs(a-0.9876)<0.0001)<<endl; //正确浮点数比较方式
cout<<(b==9876)<<endl; //整型因为能精确存储,可以精确比较
}
01
1
从输出结果中可以看到,C++中0表示false
,1表示true
。相同的浮点数,因为精度问题,在内存中存储的内容可能会有细微差别,而等于运算是一种精确的比较,导致第7行输出false
。按照科学计算的规定,第8行才是浮点数的正确比较方式。因为整型能精确存储,因此可以精确比较。
3.3 变量定义
当定义一个变量时,例如int a=1;
。根据数据类型在内存中分配对应的空间,int
类型分配4字节空间。然后将变量a
和这个空间绑定。按照整型的存储标准,将1转换为二进制,存储到对应的空间中。当后继代码使用a
时,将读取这块空间,并按照整型的存储标准进行解读。以下代码通过占位符将整型变量按照浮点数方式解读,将浮点数按照整型存储方式进行解读,虽然初始值都为1,但是得到的结果都是0,这就是存储内容和解读方式不对应的原因。这里不需要深究为什么结果是0,但是要清楚不同数据类型的内存结构是不一样的。
#include <iostream>
using namespace std;
int main()
{
float a=1;
int b = 1;
printf("%d\n",a);
printf("%f\n",b);
}
4. 字符类型
计算机中的所有内容都是以二进制形式进行存储的,数值类型可以转换为二进制存储到计算机中,但是字符是不可以的。为了存储字符,只能先把字符映射成数值,把读到的数值按照字符进行理解。国际统一的字符映射表称为ASCII表。
ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 |
---|---|---|---|---|---|---|---|
0 | NUT | 32 | (space) | 64 | @ | 96 | 、 |
1 | SOH | 33 | ! | 65 | A | 97 | a |
2 | STX | 34 | “ | 66 | B | 98 | b |
3 | ETX | 35 | # | 67 | C | 99 | c |
4 | EOT | 36 | $ | 68 | D | 100 | d |
5 | ENQ | 37 | % | 69 | E | 101 | e |
6 | ACK | 38 | & | 70 | F | 102 | f |
7 | BEL | 39 | , | 71 | G | 103 | g |
8 | BS | 40 | ( | 72 | H | 104 | h |
9 | HT | 41 | ) | 73 | I | 105 | i |
10 | LF | 42 | * | 74 | J | 106 | j |
11 | VT | 43 | + | 75 | K | 107 | k |
12 | FF | 44 | , | 76 | L | 108 | l |
13 | CR | 45 | - | 77 | M | 109 | m |
14 | SO | 46 | . | 78 | N | 110 | n |
15 | SI | 47 | / | 79 | O | 111 | o |
16 | DLE | 48 | 0 | 80 | P | 112 | p |
17 | DCI | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 | 50 | 2 | 82 | R | 114 | r |
19 | DC3 | 51 | 3 | 83 | S | 115 | s |
20 | DC4 | 52 | 4 | 84 | T | 116 | t |
21 | NAK | 53 | 5 | 85 | U | 117 | u |
22 | SYN | 54 | 6 | 86 | V | 118 | v |
23 | TB | 55 | 7 | 87 | W | 119 | w |
24 | CAN | 56 | 8 | 88 | X | 120 | x |
25 | EM | 57 | 9 | 89 | Y | 121 | y |
26 | SUB | 58 | : | 90 | Z | 122 | z |
27 | ESC | 59 | ; | 91 | [ | 123 | { |
28 | FS | 60 | < | 92 | \ | 124 | | |
29 | GS | 61 | = | 93 | ] | 125 | } |
30 | RS | 62 | > | 94 | ^ | 126 | ` |
31 | US | 63 | ? | 95 | _ | 127 | DEL |
只需要知道这个表的存在,了解每个字符在计算机中实际上是一个整数。并不需要记住每个字符对应的数值。但是有一些规律是需要知道的。
- 数字字符是连续的,小写字符是连续的,大写字符是连续的,但是大写和小写字符是不连续的。
对于一个字符,可以通过加减运算转换为另外一个字符,两个字符相减可以得到二者之间在ASCII码表上的差距,但是两个字符相加是没有物理含义的。
#include <iostream>
using namespace std;
int main()
{
char b = 'b';
cout<<b<<", "<<(int)b<<endl;
b = b-'a'+'A';
cout<<b<<", "<<(int)b<<endl;
return 0;
}
b, 98B, 66
第5行中的
b
是一个变量,'b'
是一个常量字符,必须能将二者进行清晰区分。- 第6行将变量b分别以
char
类型和int
类型进行输出,int
类型的输出实际上就是该字符的ASCII码值。其中(int)b
表示将b
强制转换为int
类型进行输出,但是b
本身没有发生任何改变。 - 将一个浮点型强制转换为整型时,小数部分会被舍掉,并不会发生四舍五入。例如
int a = (int)2.7;
。则a
的值为2
。 - 第7行将一个小写字母转换为对应的大写字母。因为字符本身的连续性,因此对应大小写字母之间的差值都是相等的,即
'a'-'A'
。很多初学者将其写为b=b-32;
。虽然结果是正确的,但是32不具有实际含义,代码阅读性差,强烈建议采用第7行的方式进行大小写字母转换。
练习:将一个数字字符转换为对应的数字,例如将'5'
转换为5。
5. 布尔类型
C/C++中的布尔值为true
/false
,其实这是两个宏,本质上就是1/0。这是布尔值和整型值的对应关系。但是整型值映射到布尔值有一个特殊的规定:非0值映射为true
,0映射为false
。例如代码2.7中求解非0值的数量。就是充分利用了整型和布尔型之间的转换规则。
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
cin>>a>>b>>c;
cout<<((bool)a+(bool)b+(bool)c);
return 0;
}
3 0 52
输出结果中的高亮部分表示输入
- a的输入值为整数3,被强制转换为布尔类型后变成了true,随后因为加法运算需要整型值,又被作为1处理。
- 同样道理,b最终为0,c最终为1,因此输出结果为2。
6. 操作符
6.1 运算符
编程常用+
、-
、*
、/
来分别执行加、减、乘、除数学运算,用=来执行赋值操作,关系运算符>
、>=
、<
、<=
、==
、!=
与小学数学中的用法相同。特别强调,等于运算符是两个等号
**==**
,初学者常用赋值号代替等于判断,从而产生了无法预知的结果。初学者在进行等于判断的时候要特别注意=的数量。
有时为了书写方便,还会采用复合运算符+=
、-=
、*=
、/=
表示。例如a+=2
表示a=a+2
。注意a*=m+1
表示a=a*(m+1)
。
C/C++中没有幂次运算,初学者常把
^
当做幂运算符,实际上它是“位或”操作符。可以包含头文件<cmath>
,使用pow
函数进行代替。但是要特别注意,pow
的返回值为浮点数类型。
6.2 除法和整除
C/C++中除法和整除都用相同的操作符/
。二者的区别是:如果分子和分母都为整数,则商自动取整,即整除运算。如果分子和分母中有一个为浮点数,则商为浮点数。当分子和分母都为整数时,为了取得浮点数的结果,需要将其中之一强制转换为浮点数。
除法和整除的区分是初学者的常犯错误之一,常常忽略了整除而导致结果不正确。
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
cout<<(1/3)<<endl;
cout<<(1.0/3)<<endl;
cout<<(1./3)<<endl;
int a=1,b=3;
cout<<(a/b)<<endl;
cout<<((float)a/b)<<endl;
cout<<(float(a)/b)<<endl;
return 0;
}
00.333333
0.333333
0
0.333333
0.333333
- 第8行将1写为1.后,也将1作为浮点数。
第11行是类型强制转换,形成了一个新的浮点型临时变量,第12行是用a构造一个float型对象,二者的含义不同,但达到的效果相同。
6.3 求模运算
a%b称为a对b求模(modulus) ,简言之就是求a除以b的余数,要求a和b必须都为整数。求模运算在程序设计中比较常见,主要有以下功能:
倍数判断。如果a%b==0,则a是b的倍数。
- 奇偶判断。如果a%2==0,则a是偶数,否则a为奇数。
- 取n进制的个位数。如果a%n的结果为m,则m是a作为n进制的各位数。例如153%10==3表示153在十进制下的个位数为3,153%2==1表示153在二进制下的个位数为1。
6.4 逻辑运算符
| 运算符 | 说明 | 范例 | | | —- | —- | —- | —- | | && | 逻辑与 | A && B | 如果 A 和 B 的值都为真,那么结果为真,否则结果为假。
如果 A 的值为假,那么不会计算 B 的值,这叫做短路。 | | || | 逻辑或 | A || B | 只要 A 和 B 的值一个为真,那么结果为真,否则结果为假。
如果 A 的值为真,那么不会计算 B 的值,这叫做短路。 | | ! | 逻辑非 | !A | 如果原来 A 为真,那么结果为假。如果原来 A 为假,那么结果为真。 |
因为逻辑与和逻辑或存在短路运算,所以要将重要的条件放在前面,如果前面的条件不成立,将不会考虑后面的条件。短路运算在很多场合都可以大幅提升计算的效率。
特别注意,C/C++中不支持连续比较。
#include<iostream>
using namespace std;
int main()
{
int m=4;
cout<<(3<m<5)<<endl;
m=2;
cout<<(3<m<5)<<endl;
m=6;
cout<<(3<m<5)<<endl;
}
11
1
从输出结果可以看到,无论m
为2或4或6,结果都为1,即判断结果都为true
。这是因为首先判断3<m
,无论结果是0或1,都是小于5。因此最终结果为1。如果需要进行连续关系判断,必须使用逻辑运算,即改为3<m && m<5
,才能得到预期结果。这也是初学者的常犯错误之一。
代码2.7的第7行也可以用逻辑非改写为cout<<(!!a+!!b+!!c);
,以a=3
为例,3为非0值,表示true
,则!3
表示false
,则!!3
表示true
,参与算术运算时被计算为1。同理!!0
表示0,!!5
表示1,因此计算结果和代码2.7相同。
练习:能被400整除的为闰年,或能被4整除并且不能被100整除的为闰年。完成以下程序的标记为TODO的缺失部分,闰年输出为1,否则输出为0。
#include <iostream>
using namespace std;
int main()
{
int year;
cin>>year;
cout<<( /*TODO*/ )<<endl;
return 0;
}
/注释内容/在C/C++中表示块注释
6.5 自增和自减运算
在 C++ 中,i++
(后自增)或++i
(前自增)都表示i=i+1
。i++
具有赋值运算,改变i
的值,而i+1
没有赋值运算,不改变i
的值,因此i++
和i+1
是不同的。
前自增与后自增的区别是前自增是先自增后赋值,后自增是先赋值后自增。与之类似,前自减与后自减的区别是前自减是先自减后赋值,后自减是先赋值后自减。
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int a = 100;
int b = a++;
int c = 100;
int d = ++c;
cout << "a = " << a << " b = " << b << endl;
cout << "c = " << c << " d = " << d << endl;
}
a = 101 b = 100c = 1 01 d = 101
6.6 sizeof运算符
在 C/C++ 中,sizeof 运算符用于获取一个变量或者数据类型所占的内存的字节大小。注意sizeof是一个运算符,而不是一个函数。
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int sizeofInt = sizeof(int);
int sizeofLL = sizeof(long long);
int sizeofChar = sizeof(char);
int sizeofFloat = sizeof(float);
int sizeofDouble = sizeof(double);
cout <<"sizeofInt = "<<sizeofInt<<" sizeofLL = "<<sizeofLL<<endl;
cout <<"sizeofChar = "<<sizeofChar<<endl;
cout <<"sizeofFloat = "<<sizeofFloat<<" sizeofDouble = "<<sizeofDouble<<endl;
}
sizeofInt = 4 sizeofLL = 8sizeofChar = 1
sizeofFloat = 4 sizeofDouble = 8
7. 获取用户输入
7.1 整型和浮点型的cin输入
cin
根据变量的数据类型,将输入信息进行转换,赋值给相应的变量。当遇到与当前变量类型不匹配的字符时,将会自动停止。
#include <iostream>
using namespace std;
int main ()
{
float a,b;
cin>>a>>b;
cout<<a+b<<endl;
int c,d;
cin>>c;
cout<<c<<endl;
cin>>d;
cout<<d<<endl;
}
1.2 3.44.6<br />12.34<br />12<br />0
- “空格”,“制表符”和“回车”被统称为空白符。
- 当输入数据并回车后,输入的内容被添加到一个输入缓冲区里,程序从缓冲区内读取数据。当执行到
cin
时,cin
读取缓冲区,如果缓冲区内有内容,直接从缓冲区读取。如果缓冲区为空,光标闪烁,等待用户输入。 cin
在对整型和浮点型进行输入的时候,首先忽略空白符,然后读取有效的字符进行解析,到第一个与当前变量类型不匹配的字符时停止。被读取的有效字符从缓冲区内被清除,而从第一个无效字符开始的内容依旧保留在缓冲区里。- 第6行对
a
赋值时,1.2前面的所有空白符被忽略,1.2被输入,遇到1.2后的空格时,输入自动停止。1.2被解析为浮点数并赋值给a
。被读取的内容从缓冲区内被清除,而3.4
被继续保留在缓冲区里。 - 对b进行赋值时,因为缓冲区非空,直接从缓冲区读取,3.4被赋值给b。特别注意,回车符作为第一个无效字符,被保留在缓冲区中。
- 第9行对
c
进行输入时,忽略缓冲区中残留的回车,未得到有效信息,因此光标闪烁,等待用户输入。用户输入12.34后,因为c
是整型,.
被认为是无效字符,输入停止。因此c
被赋值为12。.34
被保留在缓冲区中。 - 第9行对
d
进行输入时,遇到.34
,这是一个非法输入,标志位被设置为异常,cin
不再接受输入,直接跳过。d
被赋值为0。遇到非法输入时,可以使用
cin.clear();
重置标志位,然后使用cin.sync();
或cin.ignore();
清除缓冲区。这种操作比较复杂,初学者可以先行忽略缓冲区非法输入的问题,保证输入的合法性。
7.2 字符串的输入
与整型和浮点型类似,字符串也可以采用cin
的方式进行读取。但是因为字符串包含的字符范围比较多,只有遇到空白符时输入才结束。空白符之后的内容不会被读取。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string s;
cin>>s;
cout<<s<<endl;
}
first secondfirst<br />可以推断,`cin`方式读取的字符串中不包括空白符。如果字符串中需要包含空格,或者读入空字符串,需要采用`getline`方式,该方式需要包含`<string>`头文件。该方式读取一行字符串,并且把末尾的回车符从缓冲区中清除。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string s1,s2;
getline(cin,s1);
getline(cin,s2);
cout<<"s1:"<<s1<<endl;
cout<<"s2:"<<s2<<endl;
}
first second
s1:
s2:first second
第一行输入一个空行,第二行两个单词中间有一个空格,但是整行字符串被统一输入给s2
。
7.3 字符的输入
C++中采用cin.get()
读取一个任意字符,包括空白符。可以用cin<<
或cout.put()
输出字符。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
char a;
a = cin.get();cout.put(a);
a = cin.get();cout<<a;
a = cin.get();cout.put(a);
a = cin.get();cout<<a;
}
abab
c
c
- 注意第9行读取的字符是回车符,第10行读取的字符是字符’c’,因此字符’c’的输入才会在新行上出现。
7.4 数字和字符的混合输入
如7.1所示,无论是整型或浮点型,在读取正确的输入后,如果后继是一个空白符,空白符会被残留在缓冲区中。如果接下来读取一个字符,或者用getline
读取一个字符串,这个残留的空白符也会被作为有效字符进行输入,这与程序的目的可能存在违背。这时需要调用cin.ignore()
函数,去除缓冲区中残留的空白符。 ```cppinclude
include
using namespace std;
int main() { int num; string str; cin >> num; getline(cin,str); cout << “Number :” << num << “, String:” << str <<”#”<< endl; }
【样例输入】34<br />【样例输出】<br />Number :34, String:#<br />执行以上程序时会发现,只输入34并回车后,程序就会输出并结束。这时因为34后面的回车残留在缓冲区中,执行`getline`时,会读取一个空字符串。
```cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
int num;
string str;
cin >> num;
cin.ignore();
getline(cin,str);
cout << "Number :" << num << ", String:" << str <<"#"<< endl;
}
【样例输入】34
apple
【样例输出】
Number :34, String:apple#cin.ignore()
的作用就是从缓冲区中读取一个字符并抛弃,这样残留的回车符就被清除,执行到第11行的时候,因为缓冲区为空,光标闪烁等待用户输入。
当需要把无效字符到当前输入行的所有内容都进行清空时,可以调用
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
,这条语句需要头文件。该语句表示一直忽略到回车符。通常输入的字符串都不会那么长,比如最多只有256个字符,也可以简写为 cin.ignore(256, '\n');
。ignore函数的第一个参数表示最大抽取的字符数,第二个参数表示结束的字符。无参时表示只抽取并抛弃一个字符。
8. 时间处理
时间是一种常见数据,以例2.1展开讨论时间相关问题的处理。
例题2.1:国家安全局获得一份珍贵的材料,上面记载了一 一个即将进行的恐怖活动的信息。不过,国家安全局没法获知具体的时间,因为材料上的时间使用的是LINUX的时间戳,即是从2011年1月1日0时0吩秒开始到该时刻总共过了多少秒。此等重大的责任现在落到了你的肩上,给你该时间戳,请你计算出恐怖活动在哪一天实施? (为 了简单起见,规定一年12个月,每个月固定都是30天)
【输入】
一个整数n,表示从2011年1月1日0时0吩秒开始到该时刻过了n秒。
【输出】
输出一行,分别是三个整数y,m,d,表示恐怖活动在y年m月d日实施。
起始是一个日期,差值n是一个整数,为了计算最终结果,可以有两种方式:1)将n转换为日期,与起始日期相加求和;2)将起始日期转换为整数,求和后转换为日期类型。第一种方式在逻辑上较为顺畅,但是实际运算难度较大,因为日和月的进位都不规整。第二种方式在计算时更为顺畅。代码2.?为第二种方式。
#include<iostream>
using namespace std;
int main()
{
int seconds;
cin>>seconds;
int days = 60*60*24; //一天包含的秒数
int months = 30;
int years = months*12;
int day = seconds/days; //总共过去了多少天
int year = 2011+day/years;
day = day-day/years*years; //整除后再乘,去掉余数部分
int month = day/ months;
day = day-month* months;
cout<<year<<' '<<month+1<<' '<<day+1<<endl; //月和日都是从1开始计数
return 0;
}
【样例输入】130432457
【样例输出】
2015 3 10
- 第12行去掉余数的方法在计算中经常被使用。这与数学的概念是不一致的,这里的除法表示的是整除。
Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。Unix时间戳不仅被使用在Unix 系统、类Unix系统中,也在许多其他操作系统中被广泛采用。因为以秒为单位,数值比较大,更建议在计算时采用long long
类型,防止数值溢出。
9. 常用数学函数
在<cmath>
头文件中包括以下常用数学函数:开方sqrt
,求浮点数的绝对值fabs
,以10位底的对数log10
,以e为底的对数log
,幂运算pow
,正弦sin
,余弦cos
,四舍五入函数round
,向上取整函数ceil
。
round和ceil函数的返回值都是double类型,如果需要整型返回值,需要做显示类型转换。
10. 习题
练习2.1:已知三角形的三个边长a,b,c, 根据海伦公式编程计算三角形的面积,保留四位小数精度。海伦公式为
,其中。
【样例输入】
1 2 2
【样例输出】
0.9682
练习2.2:鸡兔同笼是中国古代的数学名题之一。大约在1500年前,《孙子算经》 中就记载了这个有趣的问题。书
中是这样叙述的:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何? 这四句话的意思是:有若干只鸡兔同在一个笼子里,从上面数,有35个头,从下面数,有94只脚。问笼中各有多少只鸡和兔?编程实现鸡兔同笼问题,输入头和脚的数量,输出鸡和兔的数量。
【样例输入】
35 94
【样例输出】
23 12