C++学习-入门到精通-【3】控制语句、赋值、自增和自减运算符

【010】掌握C++运算符:编程基础的深入研究 本文深入探讨了C++中的各种运算符,从基本的算术运算符到复杂的位运算符和条件运算符。通过详细的解释和示例代码,了解了这些运算符的功能、用法和注意事项。 阅读详情

C++学习-入门到精通-【3】控制语句、赋值、自增和自减运算符



一、什么是算法

对任何可求解的问题来说,都能够以一种特定的顺序执行一系列动作来完成。解决问题的步骤称为算法,它包含两方面的含义:

  1. 执行的动作
  2. 这些动作的执行顺序

举个例子来说明动作的执行顺序是非常重要的。
一个人早上会按照下面的算法:①起床;②脱掉睡衣;③沐浴;④更衣;⑤吃早饭;
如果上面动作的执行顺序发生改变:①起床;②脱掉睡衣;③更衣;④沐浴;⑤吃早饭;
这个从如果按照改变之后的顺序执行,那么他将会湿瀌瀌的吃早饭。
所以在程序执行过程中,语句的执行顺序也是非常重要的,所谓的程序控制,就是指定语句(动作)的执行顺序。

下面我们会讨论如何使用控制语句来进行程序控制。

二、伪代码

伪代码语句通常只描述可执行语句。所谓的可执行语句,是指转换为C++程序的代码之后会引起特定动作的语句。注意,没有涉及初始化和构造函数的声明并不是可执行语句。例如:int number;该语句仅是告诉编译器有一个类型为int的变量,需要你为它预留空间,但并没有导致任何动作的发生。

一个伪代码例子:
在这里插入图片描述

三、控制结构

C++程序中语句的执行顺序一般都是按照书写顺序,这种执行方式也被称为是顺序执行。但是在实际问题中只有顺序执行是不够,比如当只有满足条件A时,才执行语句A,否则跳过它,所以在最初的C++中使用goto语句来控制程序的语句执行顺序,这种由程序员自己指定程序下一句要执行的语句的方式被称为控制转移。但是使用goto语句程序代码,因为条理复杂,非常容易出错,所以这种使用goto控制语句执行顺序的方式被淘汰了,取而代之的是三种控制结构:顺序结构、选择结构、循环结构。只使用这三种结构,也可以实现所有的代码需求,且使用这种方式的代码条理清晰、易于调试,使得程序员的工作效率变高。

顺序结构

正常书写(非选择、非循环语句)的程序代码都是顺序结构。

选择结构

C++中提供3种选择语句:if语句(单路选择语句),if...else语句(双路选择语句),switch语句(多路选择语句)。严格来说,还可以使用if...else if...else语句作为多路选择语句。

if语句

判断一个人是否成年,我们需要根据他的年龄来进行判断,超过18岁就是成年
下面给出该选择语句的伪代码:

如果年龄大于等于18岁
	输出已成年

下面给出该选择语句的UML活动图。
在这里插入图片描述
其中实心圆点表示活动的起始位置,空心圆圈包围的实心圆点表示结束位置。菱形(判断符号)、圆角矩形(动作状态符号)、和小圆圈表示活动。这些符号通过箭头连接,箭头方向表示活动的流向。

if…else语句

继续上面的例子,超过18岁就是成年,不满18岁为未成年;
伪代码:

如果年龄大于等于18岁
	输出已成年
否则
	输出未成年

UML活动图:
在这里插入图片描述

else摇摆问题
如果没有圆括号强制指定if和else的匹配关系,else会和上一个距离最近的if进行匹配。

语句块
包含在花括号{}内部的一组语句称为一个语句块。

switch语句

UML活动图:
在这里插入图片描述

循环结构

C++中提供3种循环语句,while循环,for循环,do...while循环。在需要重复多次的执行某些语句时使用这种语句。

while语句

当变量i小于10时
	i增加1

UML活动图
在这里插入图片描述
上图中有两个菱形符号,第一个是合并符号,它的作用是将两个工作流(活动)合并成一个工作流。有多个流入,单个流出。第二个是判断符号,作用是判断条件是否成立,单个流入,多个流出。

注意,在switch的case标签中只能使用整型常量值(单个字符或整型数)

上面提到的if,else,switch,while,for,do都是C++中的关键字。在程序中不可以使用关键字作为标识符(例如:变量的名字)。所以大家需要了解到底有哪些关键字。
在这里插入图片描述
在这里插入图片描述

控制结构的小结
C++中只有三种控制结构,分别是顺序语句、选择语句、循环语句。每个C++程序都是由这些控制语句组建起来的。可以将每个控制语句用一张活动图表示。这样每张图都包含一个初始状态和结束状态,分别代表控制语句的入口点和出口点。使用这些单入口/单出口的控制语句可以很方便的构建程序,将一个语句的出口点与下一个语句的入口点连接在一起即可,因此称控制语句的这种连接方式为控制语句的堆叠。还会有另一种控制语句的连接方式——控制语句的嵌套,这种方式中,一个控制语句位于另一个控制语句的体内。

四、算法详述:计数器控制的循环

现在为了解决一个实际问题:10个学生,,打印他们的总成绩,计算并打印他们的平均成绩。

伪代码:

设置总数为0
设置成绩计数器为1

当成绩计数器小于等于10时
	提示输入下一个成绩
	输入下一个成绩
	将该成绩加到总数中
	成绩计数器加1

用总数除以10得到全班的平均成绩
打印总数
打印平均成绩

在之前的GradeBook类中增加上述功能:

// GradeBook.h
#include <iostream>
#include <string>

class GradeBook
{
public:
	explicit GradeBook(std::string);
	void setCourseName(std::string);
	std::string getCourseName() const;
	void display() const;
	void determineClassAverage() const;
private:
	std::string courseName;
};
// GradeBook.cpp
#include "GradeBook.h"
using namespace std;

GradeBook::GradeBook(string name)
{
	setCourseName(name);
}
void GradeBook::setCourseName(string name)
{
	// size()是string类的一个成员函数,返回调用它的对象的长度,
	// 还有一个相同作用的函数length(),这两个函数在这里的作用完全相同,你喜欢哪个就用哪个
	// 字符串的长度不超过25,该字符串有效
	if (name.size() <= 25)
	{
		courseName = name;
	}
	else // 长度不合法
	{
		courseName = name.substr(0, 25); // 将name的前25个字符截断,赋值给数据成员
		cerr << "Name \"" << name << "\" exceeds maximum length(25).\n"
			<< "limiting courseName to firse 25 characters.\n" << endl;
	}
}
string GradeBook::getCourseName() const
{
	return courseName;
}
void GradeBook::display() const
{
	cout << "Welcome to the Grade Book for " << getCourseName() << " !" << endl;
}

void GradeBook::determineClassAverage() const
{
	// 设置总数
	int sum = 0;
	// 设置计数器
	int count = 1;

	while (count <= 10)
	{
		cout << "Enter Grade:>";
		int grade = 0;
		cin >> grade;
		sum += grade;
		count++;
	}
	
	// 输出总成绩
	cout << "Total of all grades is " << sum << endl;
	// 输出平均成绩
	cout << "Class Average is " << sum / 10 << endl;
}

五、算法详述:标记控制的循环

上面的代码是存在缺陷的,不可能所有的班级的人数都是10人。那么我们应该如何修改,使得该程序可以处理任何个数的学生数量呢?

解决该问题的一种方法是利用一种被称为标记值(又称哑值、信号值、或标志值)的特殊值,来指示循环结束。用户在输入完所有的合法成绩之后,输入标记值来表示数据输入结束。标记控制的循环往往被称为不定数循环,因为循环的执行次数在执行之前都是未知的。显然这个标记值不可以与可接受的值相混淆,合法的成绩都是非负数,所以可以使用一个负值来作为标记值,通常使用-1作为标记值。

采用自顶向下、逐步求精的方法开发伪代码算法:顶层和第一层求精

为了开发出良好结构化的程序,自顶向下逐步求精的方法是一种非常有用的方法。我们最开始给出的是顶层的伪代码表示,即一条概括了程序总体功能的单语句:
计算全班的平均成绩
实际顶层伪代码是一个程序的总体描述。但是仅有顶层的伪代码的远远不够的,它无法表达出可以作为程序编写依据的细节。因为需要对其进行细化:将上层伪代码分解成一系列小的任务,并将它们按照要执行的顺序列出。这就是所谓的第一级求精。它的结果如下:

初始化变量
输入、求和和计算成绩的个数
计算并打印全班的总成绩和平均成绩

提示:许多程序在逻辑上可以分为三个阶段:初始化程序变量的初始化阶段,输入数据的值和程序变量做相应调整的处理阶段,计算和打印最终结果的收尾阶段

继续进行第二级求精

首先指定特定的变量。我们需要一个变量来保存输入的成绩的累加和,还需要一个变量来保存输入的成绩的数量。
所以伪代码初始化变量可以细化为:

初始化total为0
初始化count为0

伪代码输入、求和和计算成绩的个数需要一个循环语句来接收连续输入的每个成绩,由于此时不知道会输入多少个成绩,所以使用标记控制的循环。用户在输入完所有的成绩之后输入一个标记值来终止循环。
所以这句伪代码细化为:

提示用户输入第一个成绩
输入第一个成绩,可能为标记值 
当用户输入的值不是标记值时
	将该成绩累加入total中
	count增1
	提示用户输入下一个成绩
	输入下一个成绩,可能为标记值

对于伪代码计算并打印全班的总成绩和平均成绩可以细化为

如果count不等于0
	用total除以count的值设置平均成绩
	打印全班的总成绩
	打印全班的平均成绩
否则
	打印“未输入任何成绩”

当伪代码算法足以转换成C++代码时,这种自顶向下逐步求精的过程便可以结束。

在GradeBook类中实现标记控制的循环

仅有下面的函数发生变化

#include <iomanip>

void GradeBook::determineClassAverage() const
{
	// 设置总数
	int sum = 0;
	// 设置计数器
	int count = 0;

	int grade = 0; // 接收输入的成绩
	cout << "Enter Grade or -1 to quit:>";
	cin >> grade;

	// -1作为标记值
	while (grade != -1)
	{
		sum += grade;
		count++;
		cout << "Enter Grade or -1 to quit:>";
		cin >> grade;
	}

	if (count != 0)
	{
		double average = static_cast<double>(sum) / count;
		// 输出总成绩
		cout << "Total of all grades is " << sum << endl;
		// 设置浮点数格式
		cout << setprecision(2) << fixed;
		// 输出平均成绩
		cout << "Class Average is " << average << endl;
	}
	else
	{
		cout << "There are no valid grades" << endl;
	}
}

注意在最后的if…else语句中,使用了一个double类型的变量来接收平均值,这是因为整数除法结果出现小数会直接舍去。导致结果不准确。所以在这段代码中使用double类型的的变量来接收计算得到的平均成绩。并使用static_cast<>将int类型的sum强制转换为double类型。这里如果不使用强制类型转换将两个操作数之一转换为浮点数,那么变量average仍然会被一个int类型的值赋值(之后隐式转换为double类型)。

使用static_cast操作符称为显式转换。使用语法为static_cast<type>();

提示:浮点数是一个近似值,将一个浮点数当作精确值来使用可能会导致错误,比如:比较两个浮点数的大小

在上面的函数输出平均值之前,使用一个语句cout << setprecision(2) << fixed来设置浮点数的输出格式。这里的setprecision是一个参数化的流操纵符,它的参数为2,所以这里输出的浮点数保留小数点后两位数字。要使用该流操纵符必须使用预处理指令包含一个头文件#define <iomanip>。如果没有使用这个语句手动设置浮点数的精度,那么输出的浮点数一般保留小数点后面6位有效数字(默认精度为6)。

流操纵符fixed的作用是控制浮点数值以所谓的定点格式输出。类似于科学计数法,定点格式强制浮点数显示特定数量的位数,而且一旦采用了定点格式,那么就一定要显示小数点及为补足小数点后的位数会补0,即使这个浮点数是一个整数量,例如,66.00。如果没有设置定点格式,那么就会输出66。当程序中同时设置了流操纵符fixed和setprecision时,显示的值是一个四舍五入到指定小数位置的数,这个位置是由setprecision的参数决定的(仅输出发生变化,内存中的值不变)。例如:87.638输出为87.64,91.773输出为91.77。

除了使用fixed之外,还可以使用showpoint这个流操纵符强制输出小数点。如果只设置了showpoint没有设置fixed,则小数点后面的不会补0。showpoint也是一个无参的流操纵符。这些无参的流操纵符是不需要头文件iomanip的,在iostream中就有它们的定义。

六、算法详述:嵌套的控制语句

问题:

在这里插入图片描述

对上面的问题进行分析:

  1. 程序需要处理10个数据,所以可以使用计数器控制的循环;
  2. 每个考试结果都是一个数字,要么是1,要么是2;每次读入一个考试结果,程序都需要判断输入的数据是1还是2;
  3. 使用两个计数器来跟踪考试结果,一个记录输入的考试结果数量,另一个记录不合格的人数;
  4. 程序处理完所有的考试结果之后,需要判断是否有8个以上的学生通过考试;

下面我们使用自顶向下逐步求精的方法来分析上面的问题。

顶层
分析考试结果,并决定是否给予奖金;

这是该程序总体功能的描述。需要对其进行多次细化才能得到可以顺利转换为C++代码的伪代码。

第一层求精
该层将顶层分成三个部分:初始化,数据处理,输出结果;

所以该层的伪代码为:

初始化变量
输入10个考试结果,并对通过和未通过的人数进行计数
输出考试结果,并决定是否给予奖金

第二层求精

初始化变量的细化:

初始化变量student count为0
初始化变量failures为0

输入10个考试结果,并对通过和未通过的人数进行计数的细化:

当(while)student count小于10时
	提示输入一个考试结果
	输入一个考试结果
	student count增加1
	如果(if)考试结果为2
		failures增加1

输出考试结果,并决定是否给予奖金的细化:

显示通过人数的值(student count - failures)
显示failures的值
如果failures小于等于2
	输出"Bonus to instructor"

上面的伪代码的详细程序已经达到转换为C++代码的程度了,细化结束。

C++代码如下:

#include <iostream>
using namespace std;

int main()
{
	int student_count = 0;
	int failures = 0;

	while (student_count < 10)
	{
		cout << "Enter result:>";
		int result = 0;
		cin >> result;
		student_count++;
		if(result == 2)
			failures++;
	}

	cout << "Passes is " << (student_count - failures) << endl;
	cout << "failures is " << failures << endl;
	
	if (failures <= 2)
	{
		cout << "Bonus to instructor" << endl;
	}
}

运行结果:
在这里插入图片描述

C++11的列表初始化

C++11中引入了一种新的变量初始化语法。列表初始化又称统一初始化,使得程序员可以使用同一种语法来初始化任何类型的变量。

例如:

int number = 1;
// 可以写成
int number = { 1 };
// 或
int number{1};

{}表示列表初始化器。对于一个基本数据类型的变量,只放置一个值在列表初始化器中。对于一个对象,列表初始化器中可以是逗号分隔的值的列表,这些值传递给对象的构造函数。

比如一个雇员类,它有三个数据成员,雇员的名字,雇员的性别,雇员的薪水。

// 使用列表初始化器初始化一个雇员类的对象
Employee enployee = { "zhangsan", "male", 12345 };
// 或
Employee enployee{ "zhangsan", "male", 12345 };

使用列表初始化器来进行初始化还可以阻止“缩小转换”的发生,这种转换可能会导致数据的损失。例如,之前使用int i = 3.14试图将一个浮点数赋值给int类型的变量i,这个浮点数的浮点部分(.14)会被截掉,保存在变量i中的值其实是3,这导致了数据的损失——这就是一次缩小转换。这样的语句,编译器会发生警告,但是仍可以编译通过。

如果是使用列表初始化器进行这样的初始化,就无法编译通过,可以帮助程序员避免这种可能发生的非常微妙的逻辑错误。

比如:int i = { 3.14 },error。
在这里插入图片描述

七、关于变量的定义和声明两个概念

声明是对一个变量命名,如上面35行声明了i是一个int类型的变量,为其在内存中预留了空间,并设置它的值为1。
在C++中同时预留内存空间的变量声明,应该换个更确切的说法,变量定义。
由于定义也是声明,所以除非这种声明特别重要,否则一般情况下还是使用术语“声明”

八、for循环的应用

问题:
在这里插入图片描述

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

int main()
{
	// 年利率
	double rate = { 0.05 };
	// 年数
	double n = { 10 };
	// 本金
	double principal = { 1000.0 };
	// 总金额
	double amount{ 0 };

	// 打印表头
	// setw操作符设置输出域的宽度
	cout << "Year" << setw(22) << "Amount on deposit" << endl;

	// 初始化计数器为0
	int i{ 0 };
	for (i = 1; i <= n; i++)
	{
		amount = principal * pow((1 + rate), i);
		cout << setw(4) << i << setw(22) << amount << endl;
	}
}

运行结果:
在这里插入图片描述
可以看到这样输出的浮点数格式整齐,设置其格式cout << setprecision(2) << fixed;,再次输出:
在这里插入图片描述

代码中使用到的两个新函数/操作符:

计算幂:
在这里插入图片描述
该函数要求两个double类型的实参。返回一个double类型的值。需要包含cmath这个头文件。

流操纵符格式化数值的输出

在这里插入图片描述

该流操纵符的作用是设置下一个输出值应占用的域宽,代码中的setw(4)表示下一个输出值会占用4个字符的空间。

代码中使用两个有参数的流操纵符setprecision和setw,所以必须包含头文件<iomanip>。如果输出的值小于规定字符位置的宽度,在默认情况下,输出值在域宽范围内右对齐;输出的值大于规定字符位置的宽度,则扩展到整个输出值的宽度。可以使用无参流操纵符left设置左对齐,这是一种黏性设置(没有手动修改的情况下,之后的输出都是左对齐)。可以使用无参流操纵符right恢复右对齐。

测试代码:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
	// 验证setw流操纵符只影响下一个输出值
	cout << setw(5) << "Year" << 'a' << endl;
	// 记忆性的左对齐
	cout << setw(5) << left << "Year" << setw(4) << 'a' << endl;
	// 使用right恢复右对齐
	cout << setw(5) << left << "Year" << setw(4) << right << 'a' << endl;
}

运行结果:
在这里插入图片描述

性能提示:
在循环中1+rate这个表达式是不会发生变化的,所以它应该放在循环外面以避免不必要的开销。虽然计算一个表达式的开销很小,但放在循环中时,当循环次数很多时会导致这种开销被放大,使得性能下降。

九、使用switch语句继续优化GradeBook类

现在需要在GradeBook类中增加一些功能,包括接收用户输入的用字母表示(A、B、C、D、E)的成绩,输出每级成绩对应的学生人数的总结。

GradeBook.h

// GradeBook.h
#include <string>

class GradeBook
{
public:
	explicit GradeBook(std::string); // 初始化课程名
	void setCourseName(std::string); // 设置课程名
	std::string getCourseName() const; // 获取课程名
	void display() const; // 打印欢迎信息
	void inputGrades(); // 输入任意个学生成绩
	void displayGradeReport() const; // 打印输入的成绩报告
private:
	std::string courseName;
	unsigned int aCount; // 成绩为A的学生人数
	unsigned int bCount; // 成绩为B的学生人数
	unsigned int cCount; // 成绩为C的学生人数
	unsigned int dCount; // 成绩为D的学生人数
	unsigned int eCount; // 成绩为E的学生人数
};

GradeBook.cpp

#include <iostream>
#include "GradeBook.h"

using namespace std;

GradeBook::GradeBook(string name)
	:aCount(0),
	bCount(0), 
	cCount(0), 
	dCount(0), 
	eCount(0)
{
	// 调用set成员函数初始化课程名
	// 需要进行有效性检验
	setCourseName(name);
}

void GradeBook::setCourseName(string name)
{
	// 课程名长度小于等于25时,合法
	if (name.size() <= 25)
	{
		courseName = name;
	}
	else
	{
		// 为了程序的健壮性,就算课程名长度不合法
		// 也会截取前25个字符存入数据成员
		courseName = name.substr(0, 25);
		// 进行异常处理
		cerr << "Name \"" << name << "\" is exceeds miximum length(25)\n" 
			<< "Limits courseName to first 25 Characters.\n" << endl;
	}
}

string GradeBook::getCourseName() const
{
	// 返回数据成员courseName的值
	return courseName;
}

void GradeBook::display() const
{
	// 打印欢迎信息
	cout << "Welcome to the GradeBook for " << getCourseName() << "!" << endl;
}

void GradeBook::inputGrades()
{
	// 定义变量
	int grade{0}; // 暂存输入的成绩

	// 打印提示信息
	cout << "Enter the letter grades(A、B、C、D、E)." << endl
		<< "Enter the EOF character to end input." << endl;

	// 使用标记控制的循环来接收输入的成绩
	
	while ((grade = cin.get())/*读取一个字符*/ != EOF)
	{
		switch (grade)
		{
		case 'A': 
		case 'a':
			aCount++;
			break;
		case 'B':
		case 'b':
			bCount++;
			break;
		case 'C':
		case 'c':
			cCount++;
			break;
		case 'D':
		case 'd':
			dCount++;
			break;
		case 'E':
		case 'e':
			eCount++;
			break;
		case '\n': // 忽略换行符
		case '\t': // 忽略制表符
		case ' ': // 忽略空格
			break;
		default:
			cerr << "Incorrect letter grade entered." 
				<< "Enter a new grade." << endl;
			break;
		}
	} 
}

void GradeBook::displayGradeReport() const
{
	// 输入结果
	cout << "Number of students who received each letter grade:" 
		<< "\nA:" << aCount 
		<< "\nB:" << bCount
		<< "\nC:" << cCount
		<< "\nD:" << dCount
		<< "\nE:" << eCount
		<< endl;
}

test.cpp

#include <iostream>
#include "GradeBook.h"

using namespace std;

int main()
{
	GradeBook myGradeBook("CS1201 C++ programming");

	myGradeBook.display();
	myGradeBook.inputGrades();
	myGradeBook.displayGradeReport();
}

运行结果:

在这里插入图片描述

读入输入的字符

上面代码中使用cin.get从键盘读入一个字符,并把他保存在变量grade中。可能有些刚接触编程的同学有疑惑,字符不是应该由char类型的变量来保存吗,为什么这里使用一个整型类型的变量来保存呢?这是因为在内存中字符是以二进制的形式储存的,它们是通过ASCII编码转换成字符的。本质上整型类型和字符类型在内存中都是以二进制的形式保存,且整型类型的长度大于字符类型,所以可以使用整型类型的变量来保存字符。

一般情况下,赋值表达式的值就是赋值运算符左边的值。因此,赋值表达式grade = cin.get()的值等于cin.get()赋给grade的值。

输入EOF指示符

头文件中定义了EOF,它的值是-1,在程序执行中我们怎么输入一个EOF呢?直接输入-1?还是输入EOF?

都不是,“文件结束”的输入是通过在一行上输入组合键来实现的,在Linux/UNIX/OS X这些系统中是使用<ctrl> d,同时按下ctrl键和d键;在Windows系统中是使用<ctrl> z来实现的。

忽略输入的换行符、制表符和空格

往程序输入字符时,为了让程序读入字符,必须通过按键盘的回车键的方式,将它们送入计算机。每次输入一个字符,计算机其实读入了两个字符,一个有效成绩字符,一个换行符。当使用cin.get()读取一个字符时,会出现读入换行符的情况,为了避免每次读入这些符号都由default子句打印打印一条错误信息,所以在switch语句中包含了处理这些情况的子句。

C++11的类内初始化器

C++11允许程序员在类声明中的声明数据成员的同时,为它们提供默许值。

例如:

	// 使用类内初始化器,将下面的数据成员的值初始化为0
	unsigned int aCount = 0; // 成绩为A的学生人数
	unsigned int bCount = 0; // 成绩为B的学生人数
	unsigned int cCount = 0; // 成绩为C的学生人数
	unsigned int dCount = 0; // 成绩为D的学生人数
	unsigned int eCount = 0; // 成绩为E的学生人数

这不同于上面例子中的在类的构造函数对数据成员进行初始化。在之后的章节中我们会对该初始化器进行更详细的介绍。

十、流操纵符boolalpha

在C++程序中使用流插入运算符输出布尔值true和false时,程序输出会是1和0。如果想要让程序以单词形式输出,可以使用流操纵符boolalpha。

示例代码:

#include <iostream>

using namespace std;

int main()
{
	cout << boolalpha << "Logical AND (&&)"
		<< "\nfalse && false: " << (false && false) 
		<< "\nfalse && true: " << (false && true)
		<< "\ntrue && false: " << (true && false)
		<< "\ntrue && true: " << (true && true)
		<< endl;

	cout <<  "\nLogical OR (||)"
		<< "\nfalse || false: " << (false || false)
		<< "\nfalse || true: " << (false || true)
		<< "\ntrue || false: " << (true || false)
		<< "\ntrue || true: " << (true || true)
		<< endl;

	cout << "\nLogical NOT (!)"
		<< "\n!false: " << (!false)
		<< "\n!true: " << (!true)
		<< endl;
}

运行结果:
在这里插入图片描述

从结果中可以看出流操纵符boolalpha也是黏性设置;

3、掌握C++整数表达式:从基础到精通 本博文深入探讨了C++中整数表达式的使用方法,从变量声明、赋值运算符到各种运算符的优先级和应用,帮助读者掌握从基础到进阶的知识点,并通过实例分析常见错误及优化技巧,为编写高效、易读的代码奠定基础。 阅读详情

相关推荐

Kettle入门指南:从安装到数据转换实战

本文提供Kettle(Pentaho Data Integration)的完整入门指南,涵盖从Java环境安装、软件配置到核心概念(转换与作业)的详细解析。通过实战案例,手把手教你如何将文本文件数据导出到Excel,并连接MySQL数据库进行数据导入,帮助你快速掌握这一强大ETL工具的基本使用,实现高效数据搬运与转换。

weixin_29266647的博客 449

C++重学之路 4 控制语句、赋值、自增和自减运算符

4 控制语句、赋值、自增和自减运算符1 算法2 伪代码3 控制结构C++中的选择语句C++中的循环语句4 if选择语句5 if...else双路选择语句条件运算符(?:)嵌套的if...else语句else摇摆问题语句块6 while循环语句7 算法详述:计数器控制的循环关于整数除法和截尾的说明关于算术溢出的说明8 算法详述:标记控制的循环浮点数的精度和存储空间要求基本数据类型之间显示的和隐式的转换浮点数的格式化关于无符号整数的声明9 算法详述:嵌套的控制语句C++11的列表初始化10 赋值运算符11 自增

m0_59751822的博客 1323

WSL2下用QEMU模拟ARM开发板:从编译uboot到调试全流程(附常见错误解决)

本文详细介绍了在WSL2环境下使用QEMU模拟ARM开发板的完整流程,包括uboot编译、内核调试等关键步骤。通过QEMU模拟vexpress-a9开发板,开发者可以高效搭建嵌入式开发环境,解决常见错误并提升开发效率。

solidity8miner的博客 286

php中自增自减运算符,自增自减运算符详解

自增运算符++会把操作数加1,自减运算符--会把操作数减1,并且可以控制效果作用于运算之前还是之后,具有很大的便利性。自增自减运算符存在于C/C++/C#/Java/Python等高级语言中,它的作用是在运算结束前(前置自增自减运算符)或后(后置自增自减运算符)将变量的值加(或减)一。相较于这些语言中的+=和-=运算符,自增运算符更加简洁,且可以控制效果作用于运算之前还是之后,具有很大的便利性。自...

weixin_39919165的博客 846

Windows系统3D Gaussian Splatting环境搭建全攻略:从零开始到成功运行

本文详细介绍了在Windows系统上搭建3D Gaussian Splatting环境的完整流程,包括CUDA 12.6安装、Anaconda环境配置、代码获取与依赖安装等关键步骤。针对Windows平台特有的环境配置问题,提供了实用的解决方案和常见错误排查方法,帮助开发者快速实现3D Gaussian Splatting的成功运行。

weixin_30832143的博客 454

华为鸿蒙系统也能用!5分钟搞定谷歌三件套安装(附最新APK下载链接)

本文为华为鸿蒙系统用户提供了一份详尽的谷歌三件套(Google Play服务、商店及框架)手动安装指南。文章核心在于无需Root,通过ADB命令获取设备信息,并从可靠来源下载匹配版本的APK,按照正确顺序安装,从而解决海外应用依赖问题,实现5分钟快速部署。

c7d8e9的博客 6488

深入理解自增自减运算符:从基础使用到面试要点

在同一个表达式中对同一变量多次使用自增自减运算符会导致未定义行为:javaint a = 5;// 未定义行为,不同编译器可能有不同结果这种代码应该坚决避免,因为C/C++标准没有规定这类表达式的求值顺序。自增自减运算符是编程中的基础工具,正确理解它们的行为对于编写可靠、高效的代码至关重要。通过本文的分析,我们可以总结出以下关键点:单独使用时,前置与后置形式效果相同参与表达式时,前置形式先自增后使用,后置形式先使用后自增自减运算符遵循与自增运算符相同的规则。

2401_83384536的博客 744

ESP32拓展板DIY全攻略:从零打造你的传感器控制中心(附PCB设计文件)

本文详细介绍了如何从零开始DIY ESP32拓展板,打造多功能传感器控制中心。内容涵盖项目规划、硬件设计、PCB布局、制作测试全流程,并提供进阶优化建议和实战案例。特别适合嵌入式硬件爱好者学习ESP32拓展板开发,实现各类传感器的高效集成与控制。

blockchain9miner的博客 1077

python自加自减_自增自减运算符详解

自增运算符++会把操作数加1,自减运算符--会把操作数减1,并且可以控制效果作用于运算之前还是之后,具有很大的便利性。自增自减运算符存在于C/C++/C#/Java/Python等高级语言中,它的作用是在运算结束前(前置自增自减运算符)或后(后置自增自减运算符)将变量的值加(或减)一。相较于这些语言中的+=和-=运算符,自增运算符更加简洁,且可以控制效果作用于运算之前还是之后,具有很大的便利性。自...

weixin_42125770的博客 4441

用 ABAP 驾驭 OAuth 2.0:从 Authorization Code 到 SAML Bearer 的全栈落地指南

ABAP平台OAuth 2.0客户端开发实践 本文为SAP开发者详细解析ABAP平台内置OAuth 2.0客户端的使用方法,涵盖四种授权流的最佳实践: 授权流选择: Authorization Code:适用于用户交互场景 SAML 2.0 Bearer:适合已有SAML体系的企业 Client Credentials:系统间通信 Password Credentials:过渡方案(不推荐) 配置流程: 通过SE80定义Client Profile 使用SOAUTH2_CLIENT/OA2C_CONFIG配

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 309

PCL 使用点云创建数字高程模型DEM【2025最新版】

使用点云创建数字高程模型DEM,并将结果保存为高程图像。博客长期更新,本文最近更新时间为:2025年9月15日。

点云侠的博客 2294

c++ char* 改变长度重新赋值_C 、C++语言的 32 个关键字和 9 种控制语句

C 、C++语言的关键字共有 32 个,根据关键字的作用,可分其为数据类型关键字、控制语句关键字、存储类型关键字和其它关键字四类。1 数据类型关键字(12 个):(1) char :声明字符型变量或函数 (2) double :声明双精度变量或函数(3) enum :声明枚举类型 (4) float:声明浮点型变量或函数(5) int: 声明整型变量或函数 (6) long :声明长整型变量或函...

weixin_29790771的博客 302

【项目实战】YOLOV5 +实时吸烟目标检测+手把手教学+开源全部

本原创项目长期更新,旨在完成校园异常行为实时精检测,做到集成+N次开发+优化(不止局限于调包)为止,近期将不断更新以下模型+数据+标注文件+教程。关注博主,Star 一下github,一起开始美妙的目标检测之路吧~~ 文章目录本原创项目长期更新,旨在完成校园异常行为实时精检测,做到集成+N次开发+优化(不止局限于调包)为止,近期将不断更新以下模型+数据+标注文件+教程。关注博主,Star 一下github,一起开始美妙的目标检测之路吧~~一、项目展示二、项目资源共享1:训练图片:香烟图片+吸烟手势+烟雾三、

cv君的博客 13万+

c语言递归函数为什么会自减,自增自减运算符详解

自增运算符++会把操作数加1,自减运算符--会把操作数减1,并且可以控制效果作用于运算之前还是之后,具有很大的便利性。自增自减运算符存在于C/C++/C#/Java/Python等高级语言中,它的作用是在运算结束前(前置自增自减运算符)或后(后置自增自减运算符)将变量的值加(或减)一。相较于这些语言中的+=和-=运算符,自增运算符更加简洁,且可以控制效果作用于运算之前还是之后,具有很大的便利性。自...

weixin_35682020的博客 510

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

c语言从入门到精通pdf 百度云,c语言从入门到精通PDF

c语言从入门到精通PDF是一本用来学习c语言的非常实用的书。本书使用通俗的语言,丰富多彩的实例,各种各样的图片,详尽的介绍了C语言进行程序开发应该掌握的各方面知识。并且每个图例旁边都有着详细的注释,使读者更加轻松的领悟C语言程序开发想精髓,快速提高开发技能。本书十分适合初学者阅读,也适合作为开发人员查阅、参考资料。c语言从入门到精通PDF目录:第1篇 基础知识第1章 C语言概述 3视频讲解:29分...

weixin_39828960的博客 4518

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java学习教程,Java基础教程(从入门到精通)

原文链接 Java学习教程,Java基础教程(从入门到精通) Java学习教程,Java基础教程(从入门到精通) qq_38433066 2019-03-19 12:32:06 26941 收藏 1222 文章标签: java 入门 教程 学习 路线 你好,欢迎来到C语言中文网阅读"Java 教程",你将享受到免费的 Java 学习资料,以及良好的阅读体验。 这套教程适用于没有任何Java 基础,或者基础薄弱的学员,它通俗易懂,并且非常全面,30 天从入门到精通不是神话。 关.

u013328649的博客 1579

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【(1+1+2+1+2+3+到1+2+3+到+n)】2023-3-5

C++ 中的函数定义的一般形式如下:在 C++ 中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:返回类型:一个函数可以返回一个值。是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字void。函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。

浤济的专栏 772

3-C++基础 表达式和语句

循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。异常规范是 C++98 新增的一项功能,但是后来的 C++11 已经将它抛弃了,不再建议使用。位运算符作用于位,并逐位执行操作。C++ 编程语言提供了以下类型的判断语句。点击链接查看每个语句的细节。C++ 编程语言提供了以下几种循环类型。点击链接查看每个类型的细节。C++ 提供了下列的控制语句。点击链接查看每个语句的细节。

for_sun_read的博客 143

《C和C++程序员面试秘笈》第1章 C/C++程序基础

1. 一般赋值语句 & 按位与 对应的具体的数 && 逻辑与 0或1 || 逻辑或 0或1 三目运算符 有时可以代替条件判断 if/else/else if 2. C++域操作符 同名时:局部变量优先调用 C++中通过域操作符“::”来直接操作全局变量 3. i++和++i的区别 ...

liangwenhao1108的博客 323

学习C++

C++学习笔记(五) 循环和关系表达式

w1661824810的博客 447

java自学教程_Java学习教程,Java基础教程(从入门到精通)

原文链接:https://www.bilibili.com/video/BV1rE411F7j5/Java是一门面向对象编程语言,不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念。Java 不但可以用来开发网站后台、PC 客户端和 Android APP,还在数据分析、网络爬虫、云计算领域大显身手。从学术的角度讲,初学者需要花费不少时间来熟悉面向对象的概念、语...

weixin_31682257的博客 610

c++快速入门-2

将一个值赋给一个变量。例:a=3;//将3这个值赋给a赋值是从右向左,都是赋值表达式。错误示范:3=a;//不符合从右向左b-2=5;//“=”左边只能有一个变量名,不能有常数。

MSXmiao的博客 869

c++ auto用法_C 、C++语言的 32 个关键字和 9 种控制语句

C 、C++语言的关键字共有 32 个,根据关键字的作用,可分其为数据类型关键字、控制语句关键字、存储类型关键字和其它关键字四类。1 数据类型关键字(12 个):(1) char :声明字符型变量或函数 (2) double :声明双精度变量或函数(3) enum :声明枚举类型 (4) float:声明浮点型变量或函数(5) int: 声明整型变量或函数 (6) long :声明长整型变量或函...

weixin_39847728的博客 330

C语言自增/自减运算符:从原理到实战,彻底搞懂i++与++i

自增(++)和自减(--)运算符是C语言中用于变量值递增递减的一元运算符,其核心原理在于前置与后置形式对求值顺序和副作用发生时机的影响不同。理解这一机制对于编写高效、安全的底层代码至关重要,尤其在嵌入式开发、系统编程和算法实现等场景中。本文通过大量可运行的代码示例,深入解析了自增运算符在表达式求值、指针运算和循环控制中的经典应用与常见陷阱,帮助你规避因未定义行为导致的程序错误,提升代码质量。

cuemes08808的博客 555

03 - C++学习笔记 运算符、表达式和条件语句

在C++编程中,运算符、表达式和条件语句是非常重要的基础知识。它们允许我们对数据进行操作、进行条件判断和控制程序的执行流程。本篇笔记将介绍C++中常用的运算符、表达式和条件语句,并通过经典案例进行说明。

mingfeng4923的博客 1343

C语言自增自减运算符:前置与后置的差异、陷阱与最佳实践

自增(++)和自减(--)运算符是C语言中用于变量递增和递减的基础操作符,其核心原理在于返回值与副作用发生时的顺序差异。前置形式(如++i)先改变变量值再返回新值,而后置形式(如i++)则先返回原值再改变变量,这一差异在复杂表达式中会引发未定义行为。理解序列点和求值顺序是避免此类陷阱的关键,其技术价值在于编写出健壮、可移植且无歧义的代码。在嵌入式系统、底层驱动及高性能计算等对确定性和内存操作有严格要求的应用场景中,正确区分和使用这两种形式尤为重要。本文通过一个嵌入式数据采集模块中因`idx = (idx++

weixin_30378623的博客 368
上一篇: C++学习-入门到精通-【2】类、对象和字符串的介绍
下一篇: C++学习-入门到精通-【4】函数与递归入门
YKPG
博客等级 码龄6年 344粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值