《C++ Primer》笔记(04)

笔记

第 4 章 表达式

基础

左值右值

  • 右值:对象的值(内容);左值:对象的身份(位置)。
  • decltype关键字作用于结果为左值的表达式(不是变量),得引用类型;右值得指针类型。

求值顺序

  • 除逻辑与&&逻辑或||条件?:逗号,运算符外,都没有规定对象的求值顺序,故不能在表达式中改变同一对象的状态如cout << i << " " << ++i;,无法预知先计算i还是++i

算术运算符

  • 正负号 > 乘除、求余 > 加减法。都满足左结合。
  • 布尔值纳入计算时真为1,假为0计算;反过来时0为假,非0为真。
  • 整数的计算结果仍为整数,所有小数(无论正负)都直接舍弃(C++11新标准,向0靠拢)。
  • 取余运算当-m未溢出时,(-m)/n = m/(-n) = -(m/n); m%(-n) = m%n; (-m)%n = -(m%n);

逻辑和关系运算符

  • 短路求值:逻辑与&&和逻辑或||都先计算左侧,该特性可以避免下标越界等问题(将和大小的比较放在左边)。

赋值运算符

  • 右侧运算对象会被转换为左侧运算对象的类型,但用花括号的初始值列表不允许窄化且左侧为内置类型时只能包含一个值。int k; k = {3.14}; // 错误,窄化转换
  • 满足右结合律,a = b = c = 1;则三个变量都为1,要求三个变量可以按结合律进行类型转换(不论最右侧的值单独赋值的时候是否合法)。
  • 赋值运算符优先级低,赋值语句作为条件时应括号框起来。
  • 复合赋值运算符对左侧运算对象只求一次值(后者),普通赋值运算符求两次,一次作为右侧子表达式的一部分求值,另一次作为赋值运算左侧对象。

递增和递减运算符

  • 前置版返回递增后的值,后置版返回递增前的值。一般而言使用前置版本,进行普通的运算。
  • 后置版本用于在一条语句中同时实现变量的递增和对其原值的使用(即既需要递增又需要使用原值)*pbeg++
  • 未规定求值顺序,故不能有i = i++;

成员访问运算符

  • ptr->mem等价于(*ptr).mem,箭头运算符作用于指针类型,点运算符作用于对象。

条件运算符

  • 允许嵌套;由于条件运算符优先级低,使用时要带上括号(包括整体的括号)。
  • 条件运算符满足右结合,a?b:c?d:e等价于a?b:(c?d:e),而非(a?b:c)?d:e
  • 条件运算符规定了求值顺序为a->bc,取决于a的结果。

参考博客

位运算符

  • 小整型进行运算时会被提升为大整型。
  • 位操作可能影响符号位,其影响和环境有关,故仅将位运算符用于无符号类型。
  • 一位置1用位或,将对应位为1其他位为0的数进行位或运算;同理,一位置0用位与;判断位用位与。
  • 移位运算符满足左结合,其优先级低于算数,高于关系、赋值和条件,故后者要加上括号。

sizeof运算符

  • sizeof *p不会真正解引用,即使p是空指针也能找到其所指对象的类型。
  • 可以使用作用域运算符获得类成员的大小,即使没有实例。sizeof Sales_data::revenue;
  • sizeof 数组会计算整个数组占空间大小,而非转换为指针,sizeof(ia)/sizeof(*ia)得到数组大小,该式可以用constexpr关键词修饰。

逗号运算符

  • 常用于for循环中多个值递增/递减,求值从左向右。

类型转换

隐式转换

  • 小整型提升,小于int提升为int,大于的提升为可容纳的最小类型。
  • 条件中非布尔转换为布尔。
  • 初始化和赋值,转换为左侧类型。
  • 算术运算,如果包含无符号和有符号,且无符号不小于有符号,则有符号转为无符号(会产生符号转换问题,导致受限于环境的结果);无符号小于有符号则受限于环境进行转换(如果可容纳则转换为有符号,不可容纳则转换为无符号)。
  • 函数调用。
  • 特殊类型:
    • 数组转换为指针,在decltype关键字参数,取地址符、sizeoftypeid运算对象,使用引用初始化数组时不会发生。
    • 常量整数值0或字面值nullptr转换为指针,指向任意非常量的指针转换为void*,指向任意对象的指针转换为const void*
    • 指针转换为布尔类型,0false,否则为true
    • 指向非常量的指针转换为指向相应常量的指针,反之不存在。
    • 类类型定义的转换,如C风格字符串和string类型

显示转换

  • 不包含底层const的都可以用static_cast,也可用于找回存在于void*指针中的值。
  • const_cast只能用于改变底层const,可以解除const属性,不能改变类型。

练习代码

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
	/* 4.4*/
	cout << 12 / 3 * 4 + 5 * 15 + 24 % 4 / 2 << endl;

	/* 4.5*/
	cout << -30 * 3 + 21 / 5 << endl;
	cout << -30 + 3 * 21 / 5 << endl;
	cout << 30 / 3 * 21 % 5 << endl;
	cout << -30 / 3 * 21 % 4 << endl;

	/* 4.6*/
	int a;
	/*cin >> a;*/
	a = 10;
	if (a % 2 != 0) {
		cout << "Odd." << endl;
	}
	else {
		cout << "Even." << endl;
	}

	/* 4.9*/
	const char* cp = "Hello";
	if (cp && *cp) {
		cout << "True." << endl;
	}
	else {
		cout << "False." << endl;
	}

	/* 4.10*/
	int b;
	while (cin >> b) {
		b = 42;
		if (b == 42) {
			cout << "End." << endl;
			break;
		}
		else {
			cout << "B = " << b << endl;
		}
	}

	/* 4.11*/
	int c, d;
	/*cin >> c >> d;*/
	c = 2; d = 1;
	if (a > b && b > c && c > d) {
		cout << "Yes." << endl;
	}
	else {
		cout << "No." << endl;
	}

	/* 4.13*/
	double f = 3.14;
	double g;
	g = b = f;
	cout << g << ";" << b << ";" << f << endl;

	/* 4.14*/
	// if (42 = a) { }
	if (a = 42) {
		cout << a << endl;
	}

	/* 4.15*/
	int* pi;
	// pi = a = f = 0;

	/* 4.19*/
	int ival = 10;
	vector<int> vec{ 2,1 };
	int* ptr = &ival;
	if (ptr != 0 && *ptr++) {
		cout << "*ptr = " << *ptr << endl;
		cout << "*--ptr = " << *--ptr << endl;
		cout << "*ptr++ = " << *ptr++ << endl;
	}
	if (ival++ && ival) {
		cout << "ival = " << ival << endl;
		cout << "--ival = " << --ival << endl;
	}
	ival = 0;
	if (vec[ival++] <= vec[ival]) {// 未定顺序
		cout << "<=" << endl;
	}
	else {
		cout << ">" << endl;
	}

	/* 4.20*/
	vector<string> vStr{ "Hello","World","Hi","Yes" };
	auto iter = vStr.begin();
	cout << *iter++ << endl;// 输出iter指向的对象,iter指向下一个(++ 比 * 优先级高)
	cout << *iter-- << endl;
	// cout << (*iter)++ << endl;// string 没有 ++ 运算
	// cout << *iter.empty() << endl;// string 没有成员 empty,(. 比 * 优先级高)
	cout << iter->empty() << endl;// 判断iter指向对象是否为空,vector 有成员 empty
	// cout << ++ * iter << endl;// 错误
	cout << iter++->empty() << endl;// 判断iter指向对象是否为空,iter指向下一个
	cout << iter->empty() << endl;

	/* 4.21*/
	vector<int> vecInt{ 1,2,3,4,5,6,7,8,9,0 };
	for (auto& v : vecInt) {
		v = (v % 2 == 0) ? (v) : (v * 2);
	}

	for (auto v : vecInt) {
		cout << v << " ";
	}
	cout << endl;

	/* 4.22*/
	vector<int> score{ 77,15,31,89,94,72,65,68,74,99 };
	for (auto v : score) {
		cout << ((v >= 90) ? "high score" : ((v < 60) ? "fail" : ((v < 75) ? "low pass" : "pass"))) << endl;
	}
	for (auto v : score) {
		if (v >= 90) {
			cout << "high score" << endl;
		}
		else if (v < 60) {
			cout << "fail" << endl;
		}
		else if (v < 75) {
			cout << "low pass" << endl;
		}
		else {
			cout << "pass" << endl;
		}
	}

	/* 4.23*/
	string s = "word";
	string pl = s + ((s[s.size() - 1] == 's') ? "" : "s");
	cout << pl << endl;

	/* 4.27*/
	unsigned long ul1 = 3, ul2 = 7;
	cout << (ul1 & ul2) << " " << (ul1 | ul2) << " " << (ul1 && ul2) << " " << (ul1 || ul2) << endl;

	/* 4.28*/
	bool ba;// 1
	char ca;// 1
	wchar_t wca;// 2
	char16_t c16a;// 2
	char32_t c32a;// 4
	short sa;// 2
	int ia;// 4
	long la;// 4
	long long lla;// 8
	float fa;// 4
	double da;// 8
	long double lda;// 8
	cout << sizeof(ba) << " " << sizeof(ca) << " " << sizeof(wca) << " " << sizeof(c16a) << " " << sizeof(c32a) << " " << sizeof(sa) << " " << sizeof(ia) << " " << sizeof(la) << " " << sizeof(lla) << " " << sizeof(fa) << " " << sizeof(da) << " " << sizeof(lda) << endl;

	/* 4.29*/
	int x[10];
	int* p = x;
	cout << sizeof(x) / sizeof(*x) << " " << sizeof(p) / sizeof(*p) << endl;
	cout << sizeof(p) << " " << sizeof(*p) << endl;// 8, 4

	/* 4.36*/
	int i36 = 5;
	double d36 = 3.5;
	i36 *= static_cast<int>(d36);
	int i37 = 5;
	i37 *= d36;
	cout << i36 << " " << i37 << endl;

	return 0;
}
posted @ 2020-11-25 21:42  1Shen  阅读(111)  评论(0)    收藏  举报