C++Primer学习笔记第五章(5/18)表达式

操作符:

C++提供了丰富的操作符,并且支持操作符重载。标准库正式使用这些功能定义用于库类型的操作符。

 

表达式:

表达式由一个或者多个操作数通过操作符组合而成。可以简单到只有一个字面值常量或者变量,也可以由操作符以及一个或者多个操作数构成。

 

算术操作符:

按优先级降序第一组: +(), -()

按优先级降序第二组: *, /, %

按优先级降序第三组: +(), -()

 

%:

21%6=3;//正常情况的取模

-21%-6=-3//两个负数的模依然为负数

21%-6=?//具体值依赖于机器

 

 

关系操作符:

返回bool

按优先级降序第一组:

按优先级降序第二组:<, <=, >, >=

按优先级降序第三组:==, !=

按优先级降序第四组: &&

按优先级降序第五组: ||

 

短路求值(short-circuit evaluation):

逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。我们常常称这种求值策略为短路求值short-circuit evaluation”

比如:

expr1 && expr2 // logical AND

expr1 || expr2 // logical OR

仅当由 expr1 不能确定表达式的值时,才会求解 expr2。也就是说,当且仅当下列情况出现时,必须确保 expr2 是可以计算的:

1在逻辑与表达式中,expr1 的计算结果为 true。此时只有当 expr2 的值也是 true时 ,逻辑与表达式的值才为 true

2在逻辑或表达式中,expr1 的计算结果为 false。如果 expr1 的值为 false,则逻辑或表达式的值取决于 expr2 的值是否为 true

 

逻辑与操作符的用法要点:

对于逻辑与操作符,一个很有价值的用法是:如果某边界条件使 expr2 的计算变得危险,则应在该条件出现之前,先让 expr1 的计算结果为 false。例如,编写程序使用一个 string 类型的对象存储一个句子,然后将该句子的第一个单词的各字符全部变成大写,可如下实现:

     string s("Expressions in C++ are composed...");

     string::iterator it = s.begin();

     // convert first word in s to uppercase

     while (it != s.end() && !isspace(*it)) {

         *it = toupper(*it); // toupper covered in section 3.2.4 (p. 88)

         ++it;

     }

 

条件是否为true的判断:

If(val){ /*do something*/}//只要val为任意非零值,条件判断都得true

 

位操作符:

按优先级降序第一组:~位求反

按优先级降序第二组:<<左移, >>右移

按优先级降序第三组:&位与

按优先级降序第四组:^位异或

按优先级降序第五组: |位或

 

位操作与bitset相互转化:

假设某老师带了一个班,班中有 30 个学生,每个星期在班上做一次测验,只有及格和不及格两种测验成绩,对每个学生用一个二进制位来记录一次测试及格或不及格,以方便我们跟踪每次测验的结果,这样就可以用一个bitset对象或整数值来代表一次测验:

bitset<30> bitset_quiz1;    //  bitset solution

unsigned long int_quiz1 = 0; // simulated collection of bits()

老师可以设置和检查每个位。例如,假设第27位所表示的学生及格了,则可以使用下面的语句适当地设置对应的位:

bitset_quiz1.set(27);  

int_quiz1 |= 1UL<<27; (本句等价于int_quiz1 = int_quiz1 | 1UL << 27;

如果老师重新复核测验成绩,发现第 27 个学生实际上在该次测验中不及格,这时老师应把第 27 位设置为 0

bitset_quiz1.reset(27);   // student number 27 failed

int_quiz1 &= ~(1UL<<27);  // student number 27 failed

最后,可通过以下代码获知第 27 个学生是否及格:

bool status;

status = bitset_quiz1[27];       // how did student number 27 do?

status = int_quiz1 & (1UL<<27);  // how did student number 27 do?

 

 

赋值操作符:

在循环中,可以进行赋值操作符相关的化简。

int i = get_value();  // get_value returns an int

while (i != 42)

{

         // do something ...

         i = get_value();

}

可以被化简为

int i;

while ((i = get_value()) != 42)

{

         // do something ...

}

 

 

自增和自减操作符的前置和后置形式:

这两种操作符的后置形式同样对其操作数加 1(或减 1),但操作后产生操作数原来的、未修改的值作为表达式的结果。

而前置操作返回加1后的值,所以返回对象本身,是左值。而后置操作返回的则是右值。

     int i = 0, j;

     j = ++i; // j = 1, i = 1: prefix yields incremented value

     j = i++; // j = 1, i = 2: postfix yields unincremented value

建议:多使用前置操作符,少使用后置操作符,以减少程序开销

 

 

在单个表达式中组合使用解引用和自增操作:

     vector<int>::iterator iter = ivec.begin();

     // prints 10 9 8 ... 1

     while (iter != ivec.end())

     cout << *iter++ << endl; // iterator postfix increment

由于后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。子表达式 iter++ 使 iter 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。

 

sizeof操作符:

对数组做 sizeof 操作等效于将对其元素类型做 sizeof 操作的结果乘上数组元素的个数。

因为 sizeof 返回整个数组在内存中的存储长度,所以用 sizeof 数组的结果除以 sizeof 其元素类型的结果,即可求出数组元素的个数:

     // sizeof(ia)/sizeof(*ia) returns the number of elements in ia

     int sz = sizeof(ia)/sizeof(*ia);

 

逗号操作符:

逗号表达式是一组由逗号分隔的表达式,这些表达式从左向右计算。逗号表达式的结果是其最右边表达式的值。如果最右边的操作数是左值,则逗号表达式的值也是左值。此类表达式通常用于for循环:

     int cnt = ivec.size();

     // add elements from size... 1 to ivec

     for(vector<int>::size_type ix = 0;

         ix != ivec.size(); ++ix, --cnt)

         ivec[ix] = cnt;

 

复合表达式的求值:

操作数的分组结合方式取决于操作符的优先级和结合性。

各个操作符的优先级和结合性。

 

Newdelete表达式:

new delete 表达式可以动态创建和释放数组,这两种表达式也可用于动态创建和释放单个对象。

定义变量时,必须指定其数据类型和名字。而动态创建对象时,只需指定其数据类型,而不必为该对象命名。取而代之的是,new 表达式返回指向新创建对象的指针,我们通过该指针来访问此对象:

     int i;              // named, uninitialized int variable

     int *pi = new int;  // pi points to dynamically allocated,

                         // unnamed, uninitialized int

这个 new 表达式在自由存储区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针 pi

 

如果不提供显式初始化,动态创建的对象与在函数内定义的变量初始化方式相同(第 2.3.4 节)。对于类类型的对象,用该类的默认构造函数初始化;而内置类型的对象则无初始化。

     string *ps = new string; // initialized to empty string

     int *pi = new int;       // pi points to an uninitialized int

          delete pi;                           //

动态创建的对象用完后,程序员必须显式地将该对象占用的内存返回给自由存储区。C++ 提供了 delete 表达式释放指针所指向的地址空间。

一旦删除了指针所指向的对象,立即将指针置为 0,这样就非常清楚地表明指针不再指向任何对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值