标准数据类型
C++语言提供了丰富的数据类型,如整数类型、实数类型(浮点数)、字符类型等。每种数据类型均有均值范围,Dev-C++(4.9.9.2)是Windows平台下的32位编译器,基本数据类型的取值范围如表1.1所示(方括弧内的部分是可以省写的,例如,signed int与int等价)。
表 1.1
类型 | 字节长度 | 取值范围 | |
整数类型 | [signed]short | 2(16位) | |
[signed]int | 4(32位) | -2147483648~2147483647 | |
[signed]long | 4(32位) | ||
[signed]long long | 8(64位) | ||
布尔类型 | bool | 1(8位) | |
字符类型 | char | 1(8位) | |
实数类型 | float | 4(32位) | |
double | 8(64位) | ||
long double | 16(128位) |
现在的计算机普遍使用二进制(即0和1两个数码)来存储数据。二进制位(bit)是计算机存储信息的最小单位,代表1个二进制数位,其值为0或1,可以代表两个状态/数值。
8个连续的二进制位为一个字节,可以存放1个西文字符的编码(ASCII码)。1个汉字占两个字节。
表1.1列出的整数类型的取值范围均包含有负数,如果程序中需要用到的某数据类型的取值范围仅为正数,并且永远不可能取负数时,则可以使用无符号的数据类型,其取值范围如表1.2所示。
类型 | 字节长度 | 取值范围 |
unsigned short | 2 | |
unsigned long | 4 | |
unsigned int | 4 | |
unsigned long long | 8 |
使用无符号类型的整数类型,正整数的最大数据范围扩大了一倍啊。这对于某些数据规模较大的题目来说,如果不涉及负数的运算,使用无符号类型的整数类型,倒是很方便的。
sizeof函数可用于获取各数据类型的字节长度,例如获取long型字节长度可这样写:
cout<<sizeof(long);
了解所使用的编译器支持的各数据类型的字节长度很有必要,可以这样写:
cout << "int的字节长度为" << sizeof(int) << endl;
cout << "short的字节长度为" << sizeof(short) << endl;
cout << "long的字节长度为" << sizeof(long) << endl;
cout << "long long的字节长度为" << sizeof(long long) << endl;
cout << "bool的字节长度为" << sizeof(bool) << endl;
cout << "char的字节长度为" << sizeof(char) << endl;
cout << "float的字节长度为" << sizeof(float) << endl;
cout << "double的字节长度为" << sizeof(double) << endl;
cout << "long double的字节长度为" << sizeof(long double) << endl;
#include "pch.h" #include <iostream> using namespace std; int main() { cout << "int的字节长度为" << sizeof(int) << endl; cout << "short的字节长度为" << sizeof(short) << endl; cout << "long的字节长度为" << sizeof(long) << endl; cout << "long long的字节长度为" << sizeof(long long) << endl; cout << "bool的字节长度为" << sizeof(bool) << endl; cout << "char的字节长度为" << sizeof(char) << endl; cout << "float的字节长度为" << sizeof(float) << endl; cout << "double的字节长度为" << sizeof(double) << endl; cout << "long double的字节长度为" << sizeof(long double) << endl; return 0; }
#include <iostream> using namespace std; int main() { cout<<sizeof(char)<<endl; cout<<sizeof(bool)<<endl; cout<<sizeof(short)<<endl; cout<<sizeof(int)<<endl; cout<<sizeof(float)<<endl; cout<<sizeof(long)<<endl; cout<<sizeof(long long)<<endl; cout<<sizeof(double)<<endl; cout<<sizeof(long double)<<endl; return 0; }
#include <iostream> using namespace std; int main() { cout<<sizeof(unsigned short)<<endl; cout<<sizeof(unsigned int)<<endl; cout<<sizeof(unsigned long)<<endl; cout<<sizeof(unsigned long long)<<endl; return 0; }
两整数相加
输入两个整数,计算两整数相加的和。
/* 这是一个加法程序 */ #include "pch.h" #include <iostream> using namespace std; int main() { int a, b, c; //定义变量a,b,c cout << "请输入a,b的值:"; //显示提示信息 cin >> a >> b; //从键盘输入a和b的值 c = a + b; //计算a和b的和,并把结果放在c中 cout << a << "+" << b << "=" << c << endl; //显示结果 system("pause"); return 0; }
每种类型的数据都有各自的取值范围,请勿必确保所定义的数据不超过该类型数据的取值范围,否则会造成数据的溢出并产生结果错误。请注意,数据的溢出在编译和运行时并不报错,完全要靠编程者的细心和经验来保证结果的正确性。
下面的程序显示了整型数据溢出的错误。
//整型数据的溢出 #include "pch.h" #include <iostream> using namespace std; int main() { int a = 2147483647; a = a + 1; cout << "a=" << a << endl; system("pause"); return 0; }
变量a在自身加1以后,其值已经超过int型数据的取值范围,而发生错误。这就好像汽车的里程表一样,当达到最大值以后,又从最小值开始计数。
梯形面积
如图1.18所示,圣魔法学院的主教学楼平面图是一个梯形,已知梯形的上底和下底的长度分别为15公里和30公里,梯形中阴影部分为高级魔法师才能去的场所,其面积是160平方公里,求梯形面积是多少。
图 1.18
三角形的面积公式是(底*高)/2,由此可以算出梯形的高,再将高代入梯形面积公式(上底+下底)*高/2即可。
#include "pch.h" #include <iostream> using namespace std; int main() { double h = 160 / 15 *2; double s; s = h * (15 + 30) / 2; cout << "梯形的面积是:"<<s << endl; return 0; }
#include "pch.h" #include <iostream> using namespace std; int main() { double h = 160 / 15 *2; //double h = 160 * 2 / 15; cout << "三角形的高为:" << h << endl; double s; s = h * (15 + 30) / 2; cout << "梯形的面积是:"<<s << endl; return 0; }
#include "pch.h" #include <iostream> using namespace std; int main() { //double h = 160 / 15 *2; double h = 160 * 2 / 15; cout << "三角形的高为:" << h << endl; double s; s = h * (15 + 30) / 2; cout << "梯形的面积是:"<<s << endl; return 0; }
#include "pch.h" #include <iostream> using namespace std; int main() { float area, h, up=15, down=30; h = 160 * 2 / up; cout << h << endl; area = (up + down)*h / 2; cout << area << endl; system("pause"); return 0; }
#include "pch.h" #include <iostream> using namespace std; int main() { //float area, h, up=15, down=30; double area; //float h, up = 15, down = 30; double h, up = 15, down = 30; h = 160 * 2 / up; cout << h << endl; area = (up + down)*h / 2; cout << area << endl; system("pause"); return 0; }
#include "pch.h" #include <iostream> using namespace std; int main() { //float area, h, up=15, down=30; //double area; float area; //float h, up = 15, down = 30; double h, up = 15, down = 30; h = 160 * 2 / up; cout << h << endl; area = (up + down)*h / 2; cout << area << endl; system("pause"); return 0; }
常量和变量
在程序运行中,其值不能被改变的量称为常量。常量区分为不同的类型,如34、0、-4为整型常量,4.3、-1.32为实型常量,'a'、'b'为字符常量。
一般定义方法如下:
const int a = 34;
const float b = 10.01;
在程序运行中,其值可以改变的量称为变量,一个变量应该有一个名字,即标识符。
C++规定标识符只能由字母、数字、美元符和下划线等字符组成,且第一个字符必须为字母或下划线或美元符。
下面列出的是合法的标识符,也是合法的变量名。
_sum,average,Day,school_name,lotus_1_2,PASCAL,$sum
下面是不合法的标识符和变量名:
Mr.Wang,234NUM,#34,a>=b,¥1234
C++语言是区分大小写字母的,所以,SUM和sum是两个不同的变量名。
在选择变量名和其他标识符时,应注意做到“见名知意”,即选有含义的英文单词(或其缩写)作标识符,如count、total、price等。尽量少用代数符号(如a、b、c、xl、yl)作变量名,以增加程序的可读性。
下面是一个试图改变常量的错误代码。
//试图改变常量a的错误的程序 #include "pch.h" #include <iostream> using namespace std; int main() { const int a = 34; //定义了一个int型的常量a,a等于34 a = a * 5; //试图将a乘以5后再将其值赋给a cout << a << endl; system("pause"); return 0; }
const是C++程序里的关键字,表示所定义的类型为常量,我们可以看到,程序的第8行试图改变常量a的值。由于常量是不能够被改变的,所以程序在编译时将会出现如下错误:
assignment of read-only variable 'a'
另一种定义方法是用一个标识符代表一个常量,如下面的代码:
//标识符定义常量 #include "pch.h" #include <iostream> #define PRICE 34 //定义了一个符号常量 using namespace std; int main() { int number = 10; int total; total = number * PRICE; cout << "total=" << total << endl; system("pause"); return 0; }
程序中用#define定义PRICE这个标识符代表常量34,此后凡是在本源文件中出现的PRICE都代表34。用这种方法、用户能以一个简单的名字代替一个长的字符串。标识符一般用大写字母表示,可以和常量一样进行运算。本程序运行结果为total=340。
使用符号变量的好处是含义清楚,在需要改变一个常量时能做到“一改全改”。假设该程序中多处用到了某物品的价格,如遇到价格调整,只需改动本程序的第3行即可,如#define PRICE 100。
注意:定义符号变量语句末尾无分号。
整数常量称为整常量,除正常十进制表示方法外,整常量的特殊表示方法如下:
一个整常量后面加一个字母U或u,认为是unsigned int型,如1234u,在内存中按unsigned int规定的方式存放。
一个整常量后面加一个字母L或l,则认为是long int型常量。例如1234l、423L等。
一个整常量以数字0开头的数是八进制数。例如0234表示八进制数234,即,其值为2*8^2+3*8^1+4*8^0,等于十进制数156;-011表示八进制数-11,即十进制数-9。
一个整常量以0x开头的数是十六进制数。如0x123,代表十六进制数123,即=1*16^2+2*16^1+3*16^0=291;-0x12等于十进制-18。
实数又称浮点数。实数有两种表示方法:
(1) 十进制小数形式,它由数字和小数点组成。如.234、1234.、1234.0、0.0。
(2) 指数形式。如234e3或234E3都代表234*10^3。注意字母e(或E)之前必须有数字,且e后面的指数必须为整数。
由于实数在内存中的存放是用有限的存储单元存储的,所以能提供的有效数字总是有限的,在有效位以外的数字将会被舍去。由此可能会产生一些误差。
下面的程序演示浮点数的舍入误差:
//浮点数舍入误差演示 #include "pch.h" #include <iostream> using namespace std; int main() { float a, b, c; a = 2345678900.000;//定义一个很大的浮点数 b = 3;//定义一个很小的浮点数 cout << a << endl; c = a + b; cout << c << endl; system("pause"); return 0; }
这是由于float类型的变量只能保证7位有效数字,后面的数字是无意义的,并不能准确地表示该数。例如定义float f=123456.111;当运行cout<<f语句输出f时,结果为123456。如果将f改为double型,则能全部接收上述数字并存储在变量f中。
所以在使用实型数据时一定要格外注意实型数据的舍入误差。没有特别需要,尽可能少用实型数据。以免产生不必要的误差而影响结果的正确性。
另外,应避免将一个很大的浮点数和一个很小的数直接相加或相减,这样会“丢失”小的数。
字符和字符串
字符变量包括字符型变量和字符串变量。
字符变量是用单撇号括起来的一个字符,如'a','x','?','$'等。
字符串变量是一对双撇号括起来的字符序列。如"Good Morning!","a "," $ 34567"都是字符串变量。例如输出一个字符串如下:
cout<<"How do you do!";
字符变量只能有一个字符,是用单撇号括起来的。字符串变量可以有许多字符,是用双撇号括起来的。如'a'是一个字符变量,"a"是一个字符串变量。不能将字符常量与字符串常量混淆。'a'和"a"的真正区别在哪里呢?
每一个字符串的结尾有一个“字符串结束标志”,以便系统据此判断字符串是否结束。C++语言规定以字符'\0'作为字符串结束的标志,'\0'是一个ASCII码为0的字符,占一个字节。例如有一个字符串“Hello”,实际在内存中存储如图1.20所示。
H | e | l | l | o | \0 |
图 1.20
它占的内存不是5个字节,而是6个字节,最后一个字节为'\0'。但在输出时不输出'\0'。
又如,char a[]="abcd";cout<<sizeof(a);结果为5,因为有结束符'\0'。
在写字符串时不必加'\0',否则会画蛇添足。'\0'是系统自动加上的。字符串"a"实际包含2个字符:'a'和'\0',因此,把它赋给只能容纳一个字符的字符变量c="a"显然是不行的。如char a="a"是错误的。
字符变量是用来存放字符常量,请注意只能放一个字符。
字符变量的定义形式如下:
char c1,c2;
它表示c1和c2为字符型变量,各可以放一个字符,因此可以用下面语句对c1、c2赋值:
c1='a';c2='b';
字符数据在内存中实际是以该字符相对应的ASCII码存储,它的存储形式与整数的存储形式类似。这样使得字符型数据和整型数据可以通用。一个字符数据既可以以字符形式输出,也可以以整数形式输出,还可以对它们进行算术运算。
ASCII码表请参见本书的附录部分。表1.4中列出了几个常用的码表值:
表 1.4
ASCII值 | 字符 |
048 | 0 |
057 | 9 |
065 | A |
090 | Z |
097 | a |
122 | z |
下面的代码显示了字符变量与整数之间的通用性。
//字符变量与整数的通用性演示 #include "pch.h" #include <iostream> using namespace std; int main() { char c1, c2; c1 = 65; //注意此处是数字 c2 = 66; //注意此处是数字 cout << c1 << " " << c2 << endl;//因为c1、c2为字符类型,所以输出也是字符 cout << int(c1) << " " << int(c2) << endl;//此处强制转换为数字输出 system("pause"); return 0; }
显示结果如图1.21所示。
图 1.21
下例程序是大小写字母的转换。
//大小写字母转换 #include "pch.h" #include <iostream> using namespace std; int main() { char c1, c2; //c1 = 'a'; //c2 = 'b'; c1 = 'c'; c2 = 'd'; c1 = c1 - 32; c2 = c2 - 32; cout << c1 << ' ' << c2 << endl; system("pause"); return 0; }
运行结果为
从ASCII码表中我们可以看到,每一个小写字母比它相应的大写字母的ASCII码大32。C++语言允许字符数据与整数直接进行算术运算。这种处理方法增大了程序的自由度。例如,对字符做各种转换就比较方便。
恺撒加密术
古罗马时期,《高卢战记》有描述恺撒曾经使用密码来传递信息,即所谓的“恺撒加密术”,它是一种替代密码,如图1.22所示,对于信件中的每个字母,会用它后面的第t个字母代替。例如t=4时,“China”加密的规则是用原来字母后面第4个字母代替原来的字母,即字母“A”后面第4个字母是“E”,用“E”代替“A”。因此,“China”应译为“Glmre”。请编写一程序可将任意5个字符加密。
#include "pch.h" #include <iostream> using namespace std; int main() { //char* str = new char[5]; char str[5]="";//初始化 //char str[] = "";//初始化 //int* str = new int[5]; int i = 0,t; while (i<sizeof(str)) { //char a = str[i]; cin >> str[i]; i++; } cin >> t; for (int j = 0;j < sizeof(str);j++) { /* if (65 <= int(str[j]) <= 90&&int(str[j])+t>90) { break; } else if (97<=int(str[j])<=122&&int(str[j])+t>122) { break; } */ /* if (str[j] + t > 'Z' || str[j] + t > 'z') { break; } */ //str[j] = int(str[j]) + t; str[j] = str[j] + t; } cout << str << endl; return 0; }
改进的加密术
请编写一个程序,在程序运行时输入任意5个字符,再输入一个值t(-8<t<8),则原先的5个字符将用后面第t个字母代替并输出。
伪代码为
1 2 3 4 5 6 |
定义5个字符变量 定义t值 输入5个字符变量的值 输入t值 5个字符以其后面第t个字母代替 输出5个字符 |
#include "pch.h" #include <iostream> using namespace std; int main() { char str[5] = ""; int i = 0,t; while (i < sizeof(str)) { cin >> str[i]; i++; } cin >> t; for (int j = 0;j < sizeof(str)&&-8<t<8;j++) { str[j] = str[j] + t; } cout << str << endl; return 0; }
C++还允许一种特殊形式的字符常量,就是以一个“\”开头的字符序列。例如前面我们已经用过的'\n',它代表一个“换行”符。这是一种“控制字符”,是不能在屏幕上显示的。在程序中也无法用一个一般形式的字符表示,只能采用特殊形式来表示。
表1.5所示是以'\'开头的特殊字符(转义字符)。
表 1.5
字符形式 | 含义 | ASCII代码 |
\n | 换行,将当前位置移到下一行 | 10 |
\t | 水平制表(跳到下一个tab位置) | 9 |
\b | 退格,将当前位置移到前一列 | 8 |
\r | 回车,将当前位置移到本行开头 | 13 |
\f | 换页,将当前位置移到下页开头 | 12 |
\\ | 反斜杠字符"\" | 92 |
\' | 单撇号字符 | 39 |
\" | 双撇号字符 | 34 |
\ddd | 1到3位8进制数所代表的字符 | |
\xhh | 1到2位16进制数所代表的字符 |
通过转义字符,我们就可以在屏幕上输出诸如'\',''',' '' '之类的字符了。
注意,转义字符变量必须用单撇号括起来,不可用双撇号。双撇号用于字符串。
输出特殊字符
请在屏幕上输出如图1.23所示的字符串,注:所有字符均为英文半角。
#include "pch.h" #include <iostream> using namespace std; int main() { cout<<"He said:\"The symbol is '\\'\""<<endl; }
数据输入输出
C++的输入输出功能是由函数来实现的,例如putchar(输出字符),getchar(输入字符),cin(输入流),cout(输出流)等。
putchar 函数(字符输出函数)的作用是向终端输出一个字符。例如:
putchar(c); //输出字符变量C的值
//putchar 函数的使用 #include "pch.h" #include <iostream> using namespace std; int main() { char a = 'A', b = 'B', c = 'C'; putchar(a); putchar(b); putchar(c); system("pause"); return 0; }
getchar 函数(字符输入函数)的作用是从终端输入一个字符,其一般形式为getchar()。例如:
#include "pch.h" #include <iostream> using namespace std; int main() { char c; c = getchar(); putchar(c); system("pause"); return 0; }
请注意:getchar()只能接收一个字符,接收的字符可以赋给字符变量或整型变量也可以不赋给任何变量。如:
putchar(getchar());
puts()
向屏幕输出字符串并换行。
gets()
从键盘获得字符串,回车不算字符串。
某些情况下,程序需要以八进制或者十六进制数的形式输出结果。C++提供了简单的实现方法:只要在输出流中输出操作符dec(十进制)、oct(八进制)或hex(十六进制)即可,下面的程序分别以十进制、八进制、十六进制输出n的值。
//进制转换 #include "pch.h" #include <iostream> using namespace std; int main() { int n = 314; cout << "十进制:" << dec << n << endl;//Decimal cout << "八进制:" << oct << n << endl;//Octal cout << "十六进制:" << hex << n << endl;//Hex system("pause"); return 0; }
表1.6是常用的I/O流类库操作符,注意,设置一些特殊的格式时,我们还需使用I/O流类库提供的操纵符。使用操纵符时,首先必须在源程序的开头包含iomanip。
表 1.6
操纵符名 | 含义 |
dec | 数值数据采用十进制表示 |
hex | 数值数据采用十六进制表示 |
oct | 数值数据采用八进制表示 |
setw(int width) | 设置输出数据字段宽度为width |
ws | 提取空白符 |
setprecision(int num) | 设置浮点数精度位数 |
setfill(int ch) | 设置ch为填充字符 |
endl | 插入换行符,并刷新流 |
ends | 终止字符串 |
setprecision(int) | 设置浮点数的小数位数(包括小数点) |
setw(in) | 设置域宽 |
一旦使用了这些进制操作符,它们的作用域将一直持续到程序结束,或者遇到另一个进制操作符为止。
C++提供的setw操作符可以指定每个数值占用的宽度。为了使用setw,程序必须包括头文件iomanip,setw操作符只对紧跟着它的数值有效。如果要为多个数值设定宽度,必须多次使用setw操作符。
分析以下程序的执行结果。
put函数用于输出字符,put可以级联,如put('a').put('b')。
请看下面的程序:
#include "pch.h" #include <iostream> using namespace std; int main() { cout.put('C').put('+').put('+').put('\n'); system("pause"); return 0; }
#include <iostream> using namespace std; int main() { cout.put('C').put('+').put('+'); system("pause"); return 0; }
C++提供了输入流cin,可以利用输入流cin读取键盘输入的字符和数字等。我们可以使用I/O操作符控制输入的格式。
//输入格式控制 #include "pch.h" #include <iostream> using namespace std; int main() { int a, b, c; cout << "a:";cin >> dec >> a; cout << "b:";cin >> oct >> b; cout << "c:";cin >> hex >> c; cout << "a="<<a<<endl; cout << "b="<<b<<endl; cout << "c=" << c << endl; system("pause"); return 0; }
#include <iostream> using namespace std; int main() { int a,b,c; cout<<"a:"; cin>>dec >>a; cout<<"b:"; cin>>oct>>b; cout<<"c:"; cin>>hex>>c; cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"c="<<c<<endl; return 0; }
cin提供了get成员函数从指定的数据流中输入一个字符,并返回这个字符作为函数调用的值。
请看下面的程序:
//get成员函数的使用 #include "pch.h" #include <iostream> using namespace std; char c; int main() { c=cin.get(); cout << "c:"<<c <<endl; cout << "ASCII:" << int(c) << endl; system("pause"); return 0; }
#include <iostream> using namespace std; char c; int main() { c=cin.get(); cout<<"c:"<<c<<endl; cout<<"ASCII:"<<int(c)<<endl; system("pause"); return 0; }
cin提供了getline函数,其格式为:getline(字符串首地址,最大长度);用于将用户输入的字符串存放在“字符串首地址”指定的内存中,其最大长度不能超过“最大长度”指定的值。该函数的一个用处是可以读入一行带空格的字符串,当然gets()函数也能达到同样的效果。
下面的程序是输入一个字符序列(最大长度不超过80)并输出:
//getline的使用 #include "pch.h" #include <iostream> using namespace std; char a3[80]; int main() { cin.getline(a3,80); cout<<a3<<endl; system("pause"); return 0; }
#include <iostream> using namespace std; char a[80]; int main() { cin.getline(a,80); cout<<a<<endl; system("pause"); return 0; }
//gets_s的使用 #include "pch.h" #include <iostream> using namespace std; char a4[80]; int main() { gets_s(a4); cout << a4<< endl; return 0; }
#include <iostream> using namespace std; char a[80]; int main() { gets(a); cout<<a<<endl; return 0; }
我看附录中C语言的输入输出语句,即scanf和printf也完全可以完成以上的格式控制,而且还特别好用,速度也非常快。
建议在大批量读写数据时,使用C语言的输入输出语句。
【上机实践】 格式练习
编写一个程序,按以下格式