【捡起C++】处理数据
面向对象的本质是设计并扩展自己的数据类型。
为了把信息存储到计算机中,程序必须记录3个基本属性:
- 信息将存储在哪里
- 要存储什么值
- 存储何种类型的信息
int braincount;
braincount = 5;
/*
程序找到一块能存储整数的内存,将该内存标记为braincount,并将5复制到该内存单元中;然后,可在程序中使用braincount来访问该内存单元。
这些语句没有告诉这个值将存储在内存的什么位置,但程序确实记录了这种信息。可以使用&运算符来检索braincount的内存地址。
*/
变量名
以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符。
整型short、int、long和long long
不同位数的计算机下的长度有所不同。
-
short 至少 16位
-
int与short至少一样长
-
long至少32位,且至少与int一样长
-
long long至少64位,且至少与long一样长
16位的int的取值范围为 -32768 到 +32767。
sizeof运算符可返回类型或变量的长度,单位为字节。 运算符是内置的语言元素,对一个或多个数据进行运算,并生成一个值。
“字节”的含义依赖于硬件,在一个系统中,两字节的int可能是16位,另一个系统中可能是32位。
头文件 climits包含了关于整型限制的信息。例如INT_MAX为int的最大取值,CHAR_BIT为字节的位数。
#include<iostream>
#include<climits>
using namespace std;
int main(){
int n_int = INT_MAX;
short n_short = SHRT_MAX;
long n_long = LONG_MAX;
long long n_llong = LLONG_MAX;
cout << "int is " << sizeof(int) << " bytes." << endl;
cout << "int is " << sizeof n_int << " bytes." << endl;
cout << "short is " << sizeof n_short << " bytes." << endl;
cout << "long is " << sizeof n_long << " bytes." << endl;
cout << "long long is " << sizeof n_llong << "bytes." << endl;
cout << endl;
cout << "Maximum values:" << endl;
cout << "int: " << n_int << endl;
cout << "short: " << n_short << endl;
cout << "long: " << n_long << endl;
cout << "long long: " << n_llong << endl << endl;
cout << "Minimum int value = " << INT_MIN << endl;
cout << "Bits per byte = " << CHAR_BIT << endl;
return 0;
}
C++里,新的对变量的赋值的方式
int wren(432); // alternative c++ syntax, set wren to 432
C++11初始化方式
int hamburgers = {24}; // set hamburgers to 24
int emus{7}; //set emus to 7
int rheas = {12}; //set rheas to 12
//大括号里可以不包含任何东西,这时赋零
int rocs = {};
int psychics{};
选择整型类型
int的长度通常被设置为,计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。
如果变量表示的值不可能为负,如文档的字数,则可以使用无符号类型,这样变量可以表示更大的值。
**如果知道变量可能表示的整数值大于16位,则使用long,即使int为32位。**这样将程序移植到16位系统时,就不会突然无法正常工作。
如果存储的值超过20亿,可使用long long。
如果short比int小,则使用short可以节省内存。仅当有大型整型数组时,才有必要使用short。如果节省内存很重要,则使用short而不是int,即使它们的长度是一样的。例如,将程序从int为16位的系统移植到int为32位的系统,则存储int数组的内存量将加倍,但short数组不受影响。
如果只需要一个字节,可以使用char。
整型字面值
#include<iostream>
using namespace std;
int main(){
int chest = 42;
int waist = 0x42;
int inseam = 042;
cout << "Monsieur cuts a striking figure!\n";
cout << "chest = " << chest << " 42 in decimal\n";
cout << "waist = " << waist << " 0x42 in hex\n";
cout << "inseam = " << inseam << " 042 in octal\n";
return 0;
}
#include<iostream>
using namespace std;
int main(){
int chest = 42;
int waist = 42;
int inseam = 42;
cout << "Monsieur cuts a striking figure!\n";
cout << "chest = " << chest << " 42 in decimal\n";
cout << hex; // 修改cout显示整数的方式
cout << "waist = " << waist << " 0x42 in hex\n";
cout << oct; // manipulator for changing number base
cout << "inseam = " << inseam << " 042 in octal\n";
return 0;
}
C++如何确定常量的类型
cout << "Year = " << 1492 << endl;
除非有用特殊的后缀来表示特定的类型,或者值太大,不能存储为int,否则c++将整型常量存储为int类型。
整数后面的
- l 或 L 后缀表示该整数为long常量,
- u 或 U 后缀表示unsigned int常量
- ul表示unsigned long常量
- unsigned int 比 long更适合用来表示16位的地址
Char类型:字符和小整数
char 类型是另一种整型。虽然char用来处理字符,但也可以认为是比short更小的整型。
C++实现使用的是其主机系统的编码-----例如,IBM大型机使用EBCDIC编码。ASCII和EBCDIC都不能很好地满足国际需求,C++支持的宽字符类型可以存储更多的值,如国际Unicode字符集使用的值。使用wchar_t类型可能更合适。
即使通过键盘输入的数字也被视为字符,
char ch;
cin >> ch;
//输入5并按回车,上述代码将读取字符“5”,并将其对应的字符编码(ASCII编码53)存储到变量ch中。
int n;
cin >> n;
//输入5并按回车,上述代码将读取字符“5”,并将其转换为相应的数字值5,并存储到变量n中。
Char字面值
有些字符不能通过键盘输入到程序中。例如,按回车键并不能使字符串包含一个换行符;相反,程序编辑器把这种键击解释为在源代码中开始新的一行。其他一些字符也不能从键盘输入,因为c++语言赋予了它们特殊的含义。
注意,应该像处理常规字符那样处理转义序列(如\n)。也就是说,将它们作为字符常量时,应用单引号括起;将它们放在字符串中时,不要使用单引号。
通用字符名
通用字符名以 \u 或者 \U 打头。\u后面是8个十六进制位,\U后面则是16个十六进制位。这些位表示的是字符的 ISO 10646 码点,为大量字符提供了数值编码。
如果所用的实现支持扩展字符,则可以在标识符(如字符常量)和字符串中使用通用字符名。例如:
int k\u00F6rper;
cout << "Let them eat g\u00E2teau.\n";
signed char 和 unsigned char
与int不同的是,char在默认情况下既不是没有符号,也不是有符号。是否有符号由C++实现决定,开发人员需要将这种类型与硬件属性匹配起来。
char fodo; //may be signed, may be unsigned
unsigned char bar; //definitely unsigned
signed char snark; //definitely signed
signed char的范围通常是 -128 ~ +127, unsigned char 的范围通常是 0 ~ 255, 假设要用char变量存储200,在某些系统上可以,某些系统上不行。
如果使用char变量来存储标准ASCII字符,则char有没有符号都没有关系,都可以使用char。
wchar_t
8位char 可以表示基本字符集,wchar_t 可以表示扩展字符集。wchar_t 是一种整数类型,它有足够的空间,可以表示系统使用的最大扩展字符集。
cin 和 cout 将输入和输出看作是char流,因此不适于用来处理 wchar_t 类型。iostream头文件的最新版本提供了相似的工具——wcin 和 wcout,用于处理 wchar_t 流。
可以通过加上前缀 L 来指示宽字符常量和宽字符串。
wchar_t bob = L'P';
wcout << L"tall" << endl;
在支持两字节wchar_t的系统中,上述代码把每个字符存储在一个两个字节的内存单元中。
C++11 新增的类型:char16_t 和 char32_t
char16_t,无符号,16位,使用前缀u表示char16_t 字符常量和 字符串常量,u‘C’ , u"be good";
char32_t,无符号,32位,使用前缀U表示char16_t 字符常量和 字符串常量,U’R’,U"dirty rat";
char16_t ch1 = u'q';
char32_t ch2 = U'\U00000222B';
与wchar_t一样,char16_t和char32_t也都有底层类型——一种内置的整型,但底层类型可能随系统而已。
bool类型
字面值true和false 都可以通过提升转换为 int 类型,true被转换为1,而 false 被转换为 0;
```c++
int ans = true; //ans assigned 1
int promise = false; //promise assigned 0
```
另外,任何数字值或指针值都可以被隐式转换为 bool 值,任何非零值都被转换为true ,而 0 被转为false
const 限定符
const int Months = 12;
这样,便可以在程序中使用Months,而不是12了(在程序中,12可能表示一英尺有多少英寸或一打面包圈是几个,而名称 Months指出了值12表示的是什么)。
const叫限定符,因为它限定了声明的含义。
如果在声明常量时没有提供值,则该常量的值将是不确定的,且无法修改。
浮点数
计算机将浮点数分为两部分存储,一部分表示 值, 另一部分用于对值进行 放大或缩小。
打个比方,对于数字34.1245 和 34124.5,它们除了小数点的位置不同外,其他都是相同的。可以把第一个数表示为0.341245 (基准值) 和 100(缩放因子),而将第二个数表示为 0.341245(基准值相同)和 10000(缩放因子更大)。缩放因子的作用是移动小数点的位置, 术语浮点因此而得名。C++内部表示浮点数的方法与此相同,只不过是基于二进制数,因此缩放因子是2的幂,不是10的幂。
浮点类型
C++有三种浮点类型,float 、double 、long double。
//precision problems with float
#include<iostream>
using namespace std;
int main(){
float a = 2.34E+22f;
float b = a + 1.0f;
cout << "a = " << a << endl;
cout << "b - a = " << b - a << endl;
return 0;
}
//输出为
/*
a = 2.34e+22
b - a = 0
*/
2.34E+22的小数点左边有23位,加上1,就是在第23位加1,但float类型只能表示数字中的前6位或前7位,因此修改第23位的值不会有任何影响。
除法分支
如果两个操作数都是整数,则c++将执行整数除法。这意味着小数部分将被丢弃,使得最后的结果是一个整数。
如果其中有一个操作数是浮点数,则小数部分将保留,结果为浮点数。
#include<iostream>
using namespace std;
int main(){
/*
cout.setf()的作用是通过设置格式标志来控制输出形式,
其中ios_base::fixed表示:用正常的记数方法显示浮点数(与科学计数法相对应);
ios_base::floatfield表示小数点后保留6位小数。
*/
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "Integer division: 9/5 = " << 9 / 5 << endl;
cout << "Floating-point division: 9.0/5.0 = " << 9.0/5.0 << endl;
cout << "double constants: 1e7/9.0 = " << 1e7 / 9.0 << endl;
cout << "float constants: 1e7f/9.0f = " << 1e7f / 9.0f << endl;
return 0;
}
/*
Integer division: 9/5 = 1
Floating-point division: 9.0/5.0 = 1.800000
double constants: 1e7/9.0 = 1111111.111111
float constants: 1e7f/9.0f = 1111111.125000
*/
类型转换
将两个short值相加涉及到的硬件编译指令可能会与将两个long值相加不同。
-
将一种算术类型的值赋给另一种算数类型的变量时,C++将对值进行转换;
-
表达式中包含不同的类型时,C++将对值进行转换;
-
将参数传递给函数时,C++将对值进行转换。
将一个值赋给取值范围更大的类型通常不会导致什么问题。例如,将short值赋给long变量并不会改变这个值,只是占用的字节更多了而已。 **然而,将一个很大的long值(如2111222333)赋给float变量将降低精度。**因为float只有6位有效数字,因此这个值将被四舍五入为2.11122E9。
有些转换是安全的,有些是会带来麻烦的。
浮点值转换为整型会将数字截短(除掉小数部分)。其次float对于int可能太大了,这种情况下的结果与硬件有关。
以{}方式初始化时进行的转换
这种初始化方式被称为 列表初始化,这种初始化常用于给 复杂的数据类型 提供值列表。
它对类型的转换要求更为严格。不允许缩窄类型,不允许将浮点类型转换为整型。
在不同的整型之间转换或将整型转换为浮点型可能被允许,例如可将long变量初始化为int值,因为long总是至少与int一样长;相反方向的转换可能也被允许,只要int变量能够存储赋给它的long常量。
char c1 {31325}; //narrowing , now allowed;
char c2 = {66}; //allowed because char can hold 66
int x = 66;
char c3 = {x}; //not allowd , x is not constant
/*
初始化c3时,您知道x的值为66,但是编译器看来x是一个变量,其值可能很大。编译器不会跟踪下述阶段可能发生的情况:从x被初始化到它被用来初始化c3。
*/
表达式中的转换
自动转换。在计算表达式时,c++将bool、char、unsigned char、signed char和short值转为int。
short chickens = 20;
short ducks = 35;
short fowl = chickens + ducks;
/*
C++程序取得chickens和 ducks的值,并将它们转为int,最后将结果转为 fowl。
*/
如果short比int短,则unsigned short类型将被转换为int;如果长度相同,则unsigned short类型将被转换为unsigned int,这种规则确保unsigned short进行提升时不会损失数据。
C++可以通过强制类型转换机制显式的进行类型转换。强制类型转换不会改变该变量本身,而是创建一个新的、指定类型的值。
强制类型转换的通用格式如下:
(typename) value
typename (value)
第一种格式来自C语言,第二种是纯粹的C++。新格式的想法是, 要让强制类型转换就像是函数调用。
C++还引入了4个强制类型转换运算符,对它们的使用更为严格。
**static_cast (value) ** // convert value to typename type
C++11中的auto声明
在初始化声明中,如果使用关键字auto,而不指定变量的类型,编译器将把变量的类型设置成与初始值相同;
auto n = 100; //n is int
auto x = 1.5; //x is double
auto y = 1.3e12L; //y is long double
处理复杂类型,如STL中的类型时,自动推断类型的价值才能显示出来。例如对于,C++98代码:
std::vector<double> scores;
std::vector<double>:: iterator pv = scores.begin();
C++11允许重写为
std::vector<double> scores;
auto pv = scores.begin();