C++ 语言递增和递减运算符
C++ 语言递增和递减运算符
递增运算符 ++
和递减运算符 --
为对象的加 1 和减 1 操作提供了一种简洁的书写形式。这两个运算符还可应用于迭代器,很多迭代器本身不支持算术运算,此时递增和递减运算符除了书写简洁外还是必须的。
递增和递减运算符有两种形式:前置版本和后置版本。
- 前置版本的运算符首先将运算对象加 1 (或减 1),然后将改变后的对象作为求值结果。
- 后置版本也会将运算对象加 1 (或减 1),但是求值结果是运算对象改变之前那个值的副本。
//============================================================================
// Name : Yongqiang Cheng
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#include <stdio.h>//char str[15] = "abcdefg";
//unsigned long long hash_value_v1 = hash_code_v1(str);int main()
{int i = 0, j;j = ++i; // j = 1, i = 1: 前置版本得到递增之后的值printf("j = %d, i = %d\n", j, i);j = i++; // j = 1, i = 2: 后置版本得到递增之前的值printf("j = %d, i = %d\n", j, i);return 0;
}
j = 1, i = 1
j = 1, i = 2
请按任意键继续. . .
这两种运算符必须作用于左值运算对象。前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。
建议:除非必须,否则不用递增递减运算符的后置版本。优先使用前置版本递增递减运算符。
前置版本的递增运算符避免了不必要的工作,它把值加 1 后直接返回改变了的运算对象。与之相比,后置版本需要将原始值存储下来以便于返回这个未修改的内容。如果我们不需要修改前的值,那么后置版本的操作就是一种浪費。
对于整数和指针类型来说,编译器可能对这种额外的工作进行一定的优化;但是对于相对复杂的迭代器类型,这种额外的工作就消耗巨大了。建议养成使用前置版本的习惯,这样不仅不需要担心性能的问题,而且更重要的是写出的代码会更符合編程的初衷。
1. 在一条语句中混用解引用和递增运算符
如果我们想在一条复合表达式中既将变量加 1 或减 1 又能使用它原来的值,这时就可以使用递增和递减运算符的后置版本。
可以使用后置的递增运算符来控制循环输出一个 vector 对象内容直至遇到 (但不包括) 第一个负值为止:
auto pbeg = v.begin();// 输出元素直至遇到第一个负值为止while ((pbeg != v.end) && (*pbeg >= 0)){cout << *pbeg++ << endl; // 输出当前值并将 pbeg 向前动一个元素}
后置递增运算符的优先级高于解引用运算符,因此 *pbeg++
等价于 *(pbeg++)
。pbeg++
把 pbeg
的值加 1,然后返回 pbeg
的初始值的副本作为其求值结果,此时解引用运算符的运算对象是 pbeg
未增加之前的值。最终,这条语句输出 pbeg
开始时指向的那个元素,并将指针向前移动一个位置。
这种用法完全是基于一个事实,即后置递增运算符返回初始的未加 1 的值。如果返回的是加 1 之后的值,解引用该值将产生错误的结果。不但无法输出第一个元素,而且更糟糕的是如果序列中没有负值,程序将可能试图解引用一个根本不存在的元素。
2. 简洁之美
书写
cout << *iter++ << endl;
要比书写下面的等价语句更简洁、也更少出错
cout << *iter << endl;++iter;
递增运算会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。
3. 运算对象可按任意顺序求值
如果一条子表达式改变了某个运算对象的值,另一条子表达式又要使用该值的话,运算对象的求值顺序就很关键了。因为递增运算符和递减运算符会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。
程序使用 for
循环,将输入的第一个单词改成大写形式:
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it){*it = toupper(*it); // 将当前字符改成大写形式}
在上述程序中,我们把解引用 it
和递增 it
两项任务分开来完成。如果用一个看似等价的 while
循环进行代替将产生未定义的行为。问题在于:赋值运算符左右两端的运算对象都用到了 beg
,并且右侧的运算对象还改变了 beg
的值,所以该赋值语句是未定义的。
// 该循环的行为是未定义的!while (beg != s.end() && !isspace(*beg)){*beg = toupper(*beg++); // 错误:该赋值语句未定义}
编译器可能按照下面的任意一种思路处理该表达式:
*beg = toupper(*beg); // 如果先求左侧的值*(beg + 1) = toupper(*beg); // 如果先求右侧的值
也可能采取别的什么方式处理它。
References
(美) Stanley B. Lippman, (美) Josée Lajoie, (美) Barbara E. Moo 著, 王刚, 杨巨峰 译. C++ Primer 中文版[M]. 第 5 版. 电子工业出版社, 2013.
https://www.informit.com/store/c-plus-plus-primer-9780321714114
C++ 语言递增和递减运算符相关推荐
- 重载运算与类型转换——基本概念,输入和输出运算符,算术和关系运算符,赋值运算符,下标运算符,递增和递减运算符,成员访问运算符...
一.基本概念 重载的运算符时具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.和其他函数一样,重载的运算符也包含返回类型.参数列表以及函数体. 重载运算符函数的参数 ...
- C++primer 第 4 章 表达式 4.1基础 4 . 2 算术运算符 4 .3 逻辑和关系运算符 4 . 4 赋值运算符 4 .5 递增和递减运算符 4.6成员访问运算符
表达式由一个或多个运算对象(operand)组成,对表达式求值将得到一个结果(result) 字面值和变量是最简单的表达式(expression),其结果就是字面值和变量的值.把一个运算符(opera ...
- python中数字逐个递增_Python中递增和递减运算符的行为
不是运算符.它是两个运算符.运算符是身份运算符,它什么也不做. (澄清:一元运算符只用于数字,但我假设你不会期望一个假设的操作符在字符串上工作.) ++count 解析为 +(+count) 翻译成 ...
- java递减_浅谈java的自动递增和递减运算符的使用方法_java运算符_java_课课家
和C类似,java提供了丰富的快捷运算方式.这些快捷运算可使代码更清爽,更易录入,也更易读者辨读. 两种很不错的快捷运算方式是递增和递减运算符(常称作"自动递增"和"自动 ...
- C++ Primer 5th笔记(chap 14 重载运算和类型转换)递增和递减运算符
并不要求递增和递减运算符一定是类的成员函数,但是因为这个运算符改变的正好是所操作的对象的状态,所以建议将它们设为成员函数. 为了和内置版本保持一致,前置运算符应该返回递增或递减后对象的引用. 为了和内 ...
- java递减_关于Java中递增和递减运算符的有趣事实
关于Java中的递增和递减运算符,有许多有趣的事实.我们将通过示例讨论其中的一些-增量和减量运算符不能与'final'变量一起使用.这是由于与'final'关键字相关联的变量无法更改的事实- 示例pu ...
- JavaScript递增和递减运算符
JavaScript前文回顾: 认识JavaScript到初体验 JavaScript 注释以及输入输出语句 JavaScript变量的使用.语法扩展.命名规范 JavaScript数据类型简介以及简 ...
- PHP:递增/递减运算符
PHP:递增/递减运算符 PHP 支持 C 风格的前/后递增与递减运算符. 注意: 递增/递减运算符不影响布尔值.递减 null 值也没有效果,但是递增 null 的结果是 1. 递增/递减运算符 例 ...
- PHP的递增递减运算符有哪些,递增/递减运算符
PHP 支持 C 风格的前/后递增与递减运算符. Note: 递增/递减运算符不影响布尔值.递减 NULL 值也没有效果,但是递增 NULL 的结果是 1. ### 递增/递减运算符 | 例子 | 名 ...
最新文章
- 在k8s中使用gradle构建java web项目镜像Dockerfile
- python笔记总结_python学习笔记总结(1)
- SURF算法与源码分析、上
- 计算机网络第七章:网络安全
- Coolite Toolkit学习笔记九:表单布局控件FormLayout与FromPanel
- Linux7静默安装Oracle11g教程,亲测实用有效!
- linux 同步 多终端,Linux系统如何实现不同终端间的同步
- JS事件委托的概念和作用
- python处理字符串数组慢_Python字符串处理 - str/bytes
- 循环,函数,指针作业
- 易飞扬宣布完成100G CWDM4PSM4光模块量产线建设
- python开源项目博客_2020年7月最热门的Python开源项目
- 2016年前端web开发趋势总结
- 93、App Links (应用程序链接)实例
- 软交换协议比较和发展趋势 (SIP-T和SIP-I的比较)
- 【已解决】最新版本的Chrome浏览器如何设置网页编码
- Android TextView 上下滑动 左右滑动设置
- 加密解密验签概念理解
- Linux 常用命令 一顿操作猛如虎
- tortoisegit push 时提示 git did not exit cleanly (exit code 1)
热门文章
- 调试、条件处理和防御式编程
- 1.3 计算机的性能指标
- 一本英文书|让在华外资企业了解中国网络安全等级保护实施条例
- 对嵌入式Linux中的根文件系统的理解和解析
- 人工智能的“眼睛”:计算机视觉究竟有多厉害?
- android 单元测试2016,Android 单元测试
- 攻防世界--Misc文件类型
- Linux服务器配置与管理(基于Centos7.2)任务目标(四)
- 易优cms searchform 搜索标签使用方法
- Pipenet v1.7.2.1229 1CD(最新版,管网流体分析软件)