第五章 表达式(C++语言定义的操作符,使用内置类型的操作数)
一元操作符unary,如取地址操作符&,解引用操作符*
二元操作符binary,如加法操作符+,减法操作符-
5.1&5.2算数操作符、关系操作符、逻辑操作符
溢出:表达式的求值结果超出了其类型的表示范围。
关系操作符和逻辑操作符使用算术或指针类型的操作数,并返回bool类型的值:&&与,||或
string s("Expression in c++ are composed by some data and control symbols");
string::iterator it = s.begin();
while(it != s.end() && !isspace(*it)){
*it = toupper(*it);
++it;
}
cout << "convert the string to" << endl;
if(i < j < k)语句中的k与0、1相比较,关系操作符是从左开始进行计算
bool值本身可以进行if()语句的判断,bool值为真是1,为假是0.
5.3位操作符bitwise operator
char是C/C++整型数据中比较古怪的一个,其它的如int/long/short等不指定signed/unsigned时都默认是signed,但char在标准中是unsigned
0UL 表示 无符号长整型0 unsigned long
1UL 表示 无符号长整型 1 unsigned long
如果不写UL后缀,系统默认为:int, 即,有符号整数。
1.数值常数有:整型常数、浮点常数;
2.只有数值常数才有后缀说明;
3.数值常数后缀不区分字母大小写。
(1)整型常数的表示形式有:十进制形式、以0开头的八进制形式、以0x开头的十六进制形式,无二进制形式。
整型常数默认是signed int的。
对整型常数进行类型转换的后缀只有:u或U(unsigned)、l或L(long)、u/U与l/L的组合(如:ul、lu、Lu等)。例:100u; -123u; 0x123l;
(2)浮点常数的表示形式有:科学计数形式和小数点形式。
浮点常数默认是double的。
对浮点常数进行类型转换的后缀只有:f或F(单精度浮点数)、l或L(长双精度浮点数)。(注:因浮点型常数总是有符号的,故没有u或U后缀)。例:1.23e5f; 1.23l; -123.45f;
位操作符:~ 位求反 << 左移 >> 右移 & 位与 ^ 位异或 | 位或
bitset<30> bitset_quizl;
unsigned long int_quizl = 0;
bitset_quizl.set(27);使用bitset来进行赋值计算
逻辑与、逻辑或操作符采用成为“短路求值”(short-circuit evaluation)的求值策略
输入输出标准库(IO library)分别重载了位操作符 >> 和 << 用于输入和输出。
移位操作符具有中等优先级:其优先级比算术操作符低,高于关系操作符、赋值操作符、条件操作符
5.4赋值操作符
数组名是不可修改的左值,而下标和解引用操作符都返回左值。
赋值操作符的优先级低于 不等操作符 赋值操作符具有“右结合性”
5.5、5.6自增和自减操作符
尽量使用前自增操作:前置操作只需要加1后返回加1后的结果;后置操作符必须先保存操作数原来的值,以便返回未加1的值作为操作结果。
后自增操作优先级 > 解引用操作
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。可以对指针进行四种算术运算:++、--、+、-
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
vector<string*> spevc;
//读取vector对象
string pv;
while (cin >> pv) {
string *tr = new string; //指向string 的指针
*tr = pv;
spevc.push_back(tr); //push_back必须两个的类型相同 spevc为指向string的指针,而tr也必须是指针
}
//输出每个string 的内容及大小
vector<string*>::iterator iter = spevc.begin();
while (iter != spevc.end()) {
cout << "every string is " << **iter << (**iter).size() << endl; //第一个*解释的是迭代器iterator的地址,第二个*解释的是迭代器中元素的地址
cout << "every string is " << *iter << endl; //*iter的类型为std::vector<string>::iterator类型
iter++;
}
//释放各个动态分配的string对象
iter = spevc.begin();
while (iter != spevc.end()) {
delete *iter;
iter++;
}
return 0;
}
iter -> empty()调用iter所指向的string对象的成员函数empty
iter++ -> empty()调用iter所指向的string对象的成员函数empty,并使iter加1
5.7、条件操作符
语法格式:cond ?expr1:expr2;cond为条件判断表达式,为真时计算expr1。为假时计算expr2。 二元判断的最优选择
int max = i > j
? i > k ? i : k
: j > k ? j : k;
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int T;
vector<int> s;
while (cin >> T) {
s.push_back(T);
}
for (vector<int>::iterator iter = s.begin(); iter != s.end(); iter++) {
*(iter+1) = ((*iter > *(iter + 1)) ? *iter : *(iter + 1));
cout << *(iter + 1) << endl;
}
return 0;
}
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> ivec(20, 1);
;
size_t a = 0;
for (; a != ivec.size(); ++a) { //for语句中必须要有两个分隔符,隔开三个语句
if (a % 2 == 0) {
ivec[a] = ivec[a] * 2;
cout << ivec[a] << endl;
}
else
{
cout << ivec[a] << endl;
}
}
return 0;
}
// int iv, a = 0;
// while (cin >> iv)
// ivec.push_back(iv)
// for (vector<int>::iterator i = ivec.begin(); i != ivec.end(); i++) {
// if ((*i % 2) == 0) {
// *i = *i * 2;
5.8 sizeof () 操作符
返回一个对象或类型名的长度,类型为size_t 表达式的结果为编译时常量
1、对 char 类型或值为 char 类型的表达式做 sizeof 操作保证得 1。
2、对引用类型做 sizeof 操作将返回存放此引用类型对象所需的内在空间大小。
3、对指针做 sizeof 操作将返回存放指针所需的内在大小;注意,如果要获取该指针所指向对象的大小,则必须对指针进行引用。
4、操作等效于将对其元素类型做 sizeof 操作的结果乘上数组元素的个数。
5.9 逗号操作符
逗号表达式是一组由逗号分隔的表达式,这些表达式从左向右计算。逗号表达式的结果是其最右边表达式的值。
5.10 优先级
++ 的优先级高于 * 操作符
第二个规则有一个重要的例外:如果一个子表达式修改操作数的值,然后将该子表达式的结果用于另一个子表达式,这样则是安全的。例如,*++iter 表达式的自增操作修改了 iter 的值,然后将 iter(修改后)的值用作 * 操作符的操作数。对于这个表达式或其他类似的表达式,其操作数的计算次序无关紧要。而为了计算更复杂的表达式,改变操作数值的子表达式必须首先计算。这种方法很常用,不会产生什么问题。
5.11 new 和 delete 表达式
动态创建和释放数组、单个对象等。
定义变量时,必须指定其数据类型和名字。而动态创建对象时,只需指定其数据类型,而不必为该对象命名。取而代之的是,new 表达式返回指向新创建对象的指针,
对于类类型的对象,用该类的默认构造函数初始化,string类型等提供了默认构造函数;而内置类型的对象则无初始化。
int *pi = new int();
delete p;删除语句后,p没有定义,但是仍然存放了之前所指对象的地址。p所指向的内存已释放,p不再有效,变为悬垂指针。悬垂指针指向曾经存放对象的内存,但该对象已不存在。delete语句需要指向指针的对象。
const int *pci = new const int(1024);
5.12 类型转换
隐式类型转换:混合类型转换相同类型;用作条件的表达式被转换为bool类型。
最简单的转换为整型提升:对于所有比 int 小的整型,包括 char、signed char、unsigned char、short 和 unsigned short,如果该类型的所有可能的值都能包容在 int 内,它们就会被提升为 int 型,否则,它们将被提升为 unsigned int。如果将 bool 值提升为 int ,则 false 转换为 0,而 true 则转换为 1。
在使用数组时,大多数情况下数组都会自动转换为指向第一个元素的指针;
不将数组转换为指针的例外情况有:数组用作取地址(&)操作符的操作数或 sizeof 操作符的操作数时,或用数组对数组的引用进行初始化时,不会将数组转换为指针。
指向任意数据类型的指针都可转换为 void* 类型;整型数值常量 0 可转换为任意指针类型
while(cin >> s)其中,while循环条件为bool类型的值,此时给出的却是istream类类型的值,istream类型的值应该转换为bool类型。将istream类型转换为bool类型需要检验流的状态。
显式转换:强制类型转换cast,static cast、dynamic cast、const cast、reinterpret cast
dynamic_cast支持运行时识别指针或引用所指向的对象
const_cast 将转换掉表达式的 const 性质
const char *pc_str;
char *pc = string_copy(const_cast<char*>(pc_str));
static_cast 编译器隐式执行的任何类型转换都可以显式完成
reinterpret_cast 通常为操作数的位模式提供较低层次的重新解释。
旧式强制转换符号有下列两种形式:
type (expr); // Function-style cast notation
(type) expr; // C-language-style cast notation