1. 数据类型

C++中的常见数据类型包括int, long long, float, double, char, string, bool。其中int(32位)和long long(64位)表示整型,float(32位)和double(64位)表示浮点型;char表示字符,用单引号表示,一对单引号中有且仅有一个字符,空格也是一个字符,转义字符在书写上表达为多个字符,但是实际上表示单个字符;string表示字符串,用双引号表示;bool表示布尔类型,其值只能设置为truefalse,也可以用1或0代替。

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int a=67;
  5. float b=2.578;
  6. char c='a';
  7. printf("a=%d\n",a);
  8. printf("b=%.2f\n",b);
  9. printf("c=%c\n",c);
  10. return 0;
  11. }

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被称为变量,它和函数名等其他自定义符合统称为标识符。标识符可以由字母、数字和 (下划线)组合而成,变量名必须以字母或 (下划线)开头。标识符是大小写敏感的,即区分大小写,aA是两个不同的变量。以下都是合法的数据类型和标识符,建议使用有意义的名字作为变量名,在程序阅读时,通过变量名就可以理解程序的含义。

    1. int myNum = 5; // Integer (whole number)
    2. float myFloatNum = 5.99; // Floating point number
    3. double myDoubleNum = 9.987868; // Floating point number
    4. char myLetter = 'D'; // Character
    5. bool myBoolean = true; // Boolean
    6. string myText = "Hello"; // String

    代码2.1中的printf是C语言的屏幕输出方式,其中的%d%.2f%c称为占位符,分别表示整型、浮点型和字符类型,对应变量(a,b, c)的值将在占位符位置进行输出。其中%.2f表示输出的浮点数精度保留两位小数,如果是double类型,采用%.2lf的形式。printf书写比较复杂,还要进行类型控制,在C++中不推荐使用,C++的cout形式输出更加常用。cout能够自动进行类型检测,不需要书写占位符,使用更加简单方便。如果涉及精度控制等特殊要求,可以采用printf形式。

    1. #include <iostream>
    2. using namespace std;
    3. int main()
    4. {
    5. cout << "我喜欢中国石油大学(华东)" << endl;
    6. int a,b,c;
    7. double d,e,f;
    8. char g;
    9. cout << "a = " << a << " b = " << b << " c = " << c << endl;
    10. cout << "d = " << d << " e = " << e << " f = " << f << endl;
    11. cout << "g = " << g << endl;
    12. }

    我喜欢中国石油大学(华东)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。
    第二章 程序设计基础 - 图1
    图2.1 int类型的内存分配
    与之类似,long long为64位的整型,char是8位的整型。表2.1列举了<climits>头文件中定义的部分常量,从这些常量中可以看到charintlong 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停止。最后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来,就得到了对应的二进制
image.png
图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位,它的表示精度更大,但毕竟也是有限的。
第二章 程序设计基础 - 图3
图2.3 float类型的内存表示

3.2 纯小数十进制转换为二进制

纯小数十进制转换为二进制采用的经典方法称为乘2取整法。具体做法是:用2乘十进制小数,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,或者达到所要求的精度为止。最后把先得到的余数作为二进制数的高位有效位,后得到的余数作为二进制数的低位有效位,依次排列起来,就得到了对应的二进制。连接为二进制的时候从上往下,这与除2取整法是相反的。
image.png
图2.4 纯小数0.6875转换为二进制0.1011
可以尝试用该方法转换其他纯小数,就会发现除了2-n或多个2-n之和外,其他数值转换为二进制小数时都是无限的,而每个浮点数在计算机中的表示一定是有精度限制的。由此可以得到结论,绝大部分十进制小数在计算机中都是无法精确存储的
由此,在程序设计中存在一个奇异的特性,浮点数无法精确比较。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. float a=0.9876;
  6. int b = 9876;
  7. cout<<(a==0.9876)<<endl; //错误浮点数比较方式
  8. cout<<(fabs(a-0.9876)<0.0001)<<endl; //正确浮点数比较方式
  9. cout<<(b==9876)<<endl; //整型因为能精确存储,可以精确比较
  10. }

01
1
从输出结果中可以看到,C++中0表示false,1表示true。相同的浮点数,因为精度问题,在内存中存储的内容可能会有细微差别,而等于运算是一种精确的比较,导致第7行输出false。按照科学计算的规定,第8行才是浮点数的正确比较方式。因为整型能精确存储,因此可以精确比较。

3.3 变量定义

当定义一个变量时,例如int a=1;。根据数据类型在内存中分配对应的空间,int类型分配4字节空间。然后将变量a和这个空间绑定。按照整型的存储标准,将1转换为二进制,存储到对应的空间中。当后继代码使用a时,将读取这块空间,并按照整型的存储标准进行解读。以下代码通过占位符将整型变量按照浮点数方式解读,将浮点数按照整型存储方式进行解读,虽然初始值都为1,但是得到的结果都是0,这就是存储内容和解读方式不对应的原因。这里不需要深究为什么结果是0,但是要清楚不同数据类型的内存结构是不一样的。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. float a=1;
  6. int b = 1;
  7. printf("%d\n",a);
  8. printf("%f\n",b);
  9. }

00.000000

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码表上的差距,但是两个字符相加是没有物理含义的。

    1. #include <iostream>
    2. using namespace std;
    3. int main()
    4. {
    5. char b = 'b';
    6. cout<<b<<", "<<(int)b<<endl;
    7. b = b-'a'+'A';
    8. cout<<b<<", "<<(int)b<<endl;
    9. return 0;
    10. }

    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值的数量。就是充分利用了整型和布尔型之间的转换规则。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int a,b,c;
  6. cin>>a>>b>>c;
  7. cout<<((bool)a+(bool)b+(bool)c);
  8. return 0;
  9. }

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++中除法和整除都用相同的操作符/。二者的区别是:如果分子和分母都为整数,则商自动取整,即整除运算。如果分子和分母中有一个为浮点数,则商为浮点数。当分子和分母都为整数时,为了取得浮点数的结果,需要将其中之一强制转换为浮点数。

除法和整除的区分是初学者的常犯错误之一,常常忽略了整除而导致结果不正确。

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. cout<<(1/3)<<endl;
  7. cout<<(1.0/3)<<endl;
  8. cout<<(1./3)<<endl;
  9. int a=1,b=3;
  10. cout<<(a/b)<<endl;
  11. cout<<((float)a/b)<<endl;
  12. cout<<(float(a)/b)<<endl;
  13. return 0;
  14. }

00.333333
0.333333
0
0.333333
0.333333

  • 第8行将1写为1.后,也将1作为浮点数。
  • 第11行是类型强制转换,形成了一个新的浮点型临时变量,第12行是用a构造一个float型对象,二者的含义不同,但达到的效果相同。

    6.3 求模运算

    1. a%b称为ab求模(modulus) ,简言之就是求a除以b的余数,要求ab必须都为整数。求模运算在程序设计中比较常见,主要有以下功能:
  • 倍数判断。如果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+1i++具有赋值运算,改变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()函数,去除缓冲区中残留的空白符。 ```cpp

    include

    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类型,如果需要整型返回值,需要做显示类型转换。

例题2.2:求一个整数的位数
(int)log10(x)+1

10. 习题

练习2.1:已知三角形的三个边长a,b,c, 根据海伦公式编程计算三角形的面积,保留四位小数精度。海伦公式为
第二章 程序设计基础 - 图5,其中第二章 程序设计基础 - 图6
【样例输入】
1 2 2
【样例输出】
0.9682
练习2.2:鸡兔同笼是中国古代的数学名题之一。大约在1500年前,《孙子算经》 中就记载了这个有趣的问题。书
中是这样叙述的:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何? 这四句话的意思是:有若干只鸡兔同在一个笼子里,从上面数,有35个头,从下面数,有94只脚。问笼中各有多少只鸡和兔?编程实现鸡兔同笼问题,输入头和脚的数量,输出鸡和兔的数量。
【样例输入】
35 94
【样例输出】
23 12