c++ primer(第五版)笔记 第四章 表达式

31 篇文章 0 订阅
#include<iostream>
#include<vector>
#include<string>
#include<cstddef>

using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::vector;

void practice_4_5();
void practice_4_6();
void practice_4_20();
void practice_4_21();
void practice_4_29();
class Test
{
public:
	int a = 0;
	char c = 'c';
};

int main()
{
	//一元运算符(unary operator)	作用于一个运算对象(operand)		如:取地址符(&),解引用符(*)
	//二元运算符(binary operator)	作用于二个运算对象(operand)		如:乘法(*)
	//三元运算符(ternary operator)	作用于三个运算对象(operand)		如:条件运算符(?:)

	//左值(lvalue),使用的是对象的身份(内存中的位置),可以代替右值
	//右值(rvalue),使用的是对象的值(内容),不可以代替左值

	//和左值有关的运算符:
	//赋值运算符(=)将可修改的左值作为其左侧的运算对象,其结果也是一个左值
	//取地址符(&)作用于一个左值对象,结果是指向该对象的指针,是一个右值
	//内置解引用符,下标运算符,迭代器的解引用,string 和 vector 的下标运算符,其结果是一个左值
	//内置类型和迭代器的递增递减运算符,作用于一个左值对象,前置版本其结果也是一个左值,后置版本将对象原始值的副本作为右值返回
	//箭头运算符指向一个指针类型的运算对象,结果是一个左值
	//点运算符,如果作用对象是左值,则返回结果也是左值,如果是右值,则结果也是右值
	//条件运算符,当2个表达式都是左值或者可以转换成同一种的左值类型时,其返回结果为左值,否则为右值

	//如果 decltype 作用的表达式结果为一个左值,则 decltype 返回的类型是一个引用
	int i = 10, *p = &i;
	decltype(*p) r = i;			//解引用运算返回一个左值,所以 r 是一个 int &.
	decltype(&i) pi = nullptr;	//取地址运算返回一个右值, pi 是一个 int *.

	//c++ 规定了运算对象的结合方式,但没有说明运算对象按什么顺序求值
	cout << i << " " << ++i << endl;	//不同的编译器计算 i 的顺序不同,结果未定义,错误的书写
	//当改变了某个运算对象的值,在表达式中不要再使用该对象,除非改变对象的子表达式是另一个子表达式的运算对象
	int arr[3]{0, 1, 3}, *pa = arr;
	cout << *++pa << endl;	//按优先级,先计算 ++pa, 然后解引用,无异议

	//四种明确求值顺序的运算符:
	//逻辑与(&&),逻辑或(||),条件运算符(?:),逗号(,)

	//算术运算符
	//整数相除还是整数,如果有小数点,会被截断,c++11规定,向0取整,如果符号相同,结果为正,否则为负
	int ival = -19 / 3;
	cout << ival << endl;
	//取余又称取模,运算对象必须为整数,在不溢出的情况下,(-m)%n == -(m%n), m%(-n) == m%n, 也就是同 m 的符号

	practice_4_5();
	practice_4_6();

	//逻辑和关系运算符,返回布尔类型,是右值
	//逻辑与(&&),逻辑或(||) 都是短路求值(short-circuit evaluation),只有当左侧运算对象无法确定表达式结果时,才计算右侧的运算对象
	//逻辑非(!),运算对象的结果取反后返回
	//关系运算符,都满足左结合律
	int a = 1, b = 2, c = 3;
	if (a < b < c)	//先计算 a < b的比较结果为 true, 然后提升为 1, 和 c 比较
	{
		;
	}
	//比较运算时,除非比较的对象是布尔类型,否则不要用布尔字面值 true 和 false 作为运算对象
	if (b == true)	//将 true 提升为 int 1, 然后和 b 的值比较
	{
		;
	}

	//赋值运算符,如果左右两侧的对象类型不同,右侧对象会转化成左侧对象的类型,而且该值即使转化的话,其所占空间也不应该大于目标类型的空间
	//右结合律
	b = c = a = 9;	//先将 a 赋值为 9,然后将a的值赋给c,c的值给b,此过程要求每个 = 的右侧可以转化成左侧对象的类型

	//成员访问运算符
	//点运算符(.) 和箭头运算符(->)
	practice_4_20();

	//条件运算符,由于其优先级非常低,在长表达式中,要使用括号
	cout << ((a > 0) ? "true" : "false");
	//cout << (a > 0) ? "true" : "false";	//相当于 (cout << (a > 0))?"true" : "false"
	//cout << a > 0 ? "true" : "false" ;	//相当于 ((cout << a) > 0)?"true" : "false"

	practice_4_21();

	//位运算符用作整数二进制位移动的算术运算,如果是小整型,会被提升,可以是有符号类型,也可以是无符号类型,但有符类型的符号位依赖于机器,如果改变符号位,行为未定义,建议只用于无符号类型
	//左侧对象按照右侧对象的要求移动指定位数,然后将移动后(可能提升)的左侧对象的拷贝作为求值结果,右侧对象一定不能为负数,而且值严格小于结果的位数,否则产生未定义的行为
	//左移运算符(<<)在右侧插入值为 0 的二进制位
	//右移运算符(>>)如果左侧对象是无符号类型,在左侧插入值为 0 的二进制位;如果为有符号类型,在左侧插入符号位的副本或值为 0 的二进制位,依赖于环境
	//位求反运算符(~)
	//位与(&)运算对象对应位都是1,结果该位为1,否则0
	//位或(|)运算对象对应位至少一个是1,结果该位为1,否则0
	//位异或(^)运算对象对应位有且只有一个是1,结果该位为1,否则0
	//位运算符都执行左结合律

	//sizeof 运算符返回一个表达式或类型名字所占的字节数,右结合律,返回类型为 size_t 的常量表达式, 定义于 cstddef
	//对 char 或 类型为 char 的表达式执行 sizeof 结果为1
	//对引用类型进行 sizeof 运算得到被引用对象所占空间的大小
	//sizeof 指针得到指针本身所占空间的大小
	//对解引用指针进行 sizeof 运算得到所指对象占用空间的大小,指针无需有效
	//对 string 或 vector 对象执行 sizeof 得到该类型固定部分的大小,不计算其中元素占用了多少空间
	//对数组进行 sizeof 运算得到整个数组所占用空间的大小
	Test test;
	Test *pt = &test;
	string sTest = "char";
	vector<int> vTest{0};
	int arrTest[5]{4,21,62,1,76};
	cout << sizeof(Test) << endl;
	cout << sizeof(test) << endl;
	cout << sizeof Test << endl;
	cout << sizeof test << endl;
	cout << sizeof pt << endl;
	cout << sizeof *pt << endl;
	cout << sizeof(pt->c)<< endl;
	//cout << Test::c << endl;
	cout << sizeof sTest << endl;
	cout << sizeof vTest << endl;
	cout << sizeof(arrTest) << endl;
	cout << sizeof arrTest << endl;
	practice_4_29();

	//逗号运算符,自左向右结合

	//隐式转换(implicit conversion)
	//比 int 小的整型值首先提升为较大的整型类型
	//在条件中,非布尔值转换为布尔值
	//初始化时,初始值转换为变量的类型
	//在赋值中,右侧运算对象转换成左侧运算对象的类型
	//关系运算和算术运算中,需要转换成同一种类型
	//函数中类型转换

	//整型提升(intrgral promotion),把小整数类型换为大整数类型,前提是转换后的类型要能容纳原类型所有的可能值
	//算术转换,
	//首先进行整型提升,如果类型匹配,无须进一步转换,提升后,如果都是无符号的或者都是带符号的,则小类型转换为较大的类型;
	//如果一个带符号的,一个无符号的,且无符号类型不小于带符号类型,则带符号的转换为无符号的;
	//如果带符号类型大于无符号类型,结果依赖与机器,如果无符号类型的所有值都能存在于带符号类型中,则无符号类型转换为带符号类型;如果不行,则带符号的转换为有符号类型
	//数组转换为指针:decltype, sizeof, typeid, &时除外
	//指针的转换:整数值 0 和字面值 nullptr 可以转换为任何指针类型;指向任意非常量的指针都可以转换为 void *;指向任意对象的指针都可以转换为 const void *
	//转换为布尔类型:如果算术类型或指针值为0,转换结果为 false,否则为 true;
	//允许将非常量的指针或引用转换为常量的指针或引用
	
	//显式转换又叫强制类型转换(cast)
	//static_cast 只要不包含底层 const ,就可以使用
	//const_cast 只用于去掉底层 const
	//reinterpret_cast
	//旧式强制类型转换 type(expr) / (type) expr
	return 0;
}

//求表达式的值
void practice_4_5()
{
	cout << 12 / 3 * 4 + 5 * 15 + 24 % 4 / 2 << endl;	//91

	cout << -30 * 3 + 21 / 5 << endl;	//-86
	cout << -30 + 3 + 21 / 5 << endl;	//-23
	cout << 30 / 3 * 21 % 5 << endl;	//0
	cout << -30 / 3 * 21 % 4 << endl;	//-2
}

//判断输入的数奇数偶数
void practice_4_6()
{
	cout << "pls input a number:" << endl;
	int n = 0;
	while (cin >> n)
	{
		if ( n < 0)
		{
			cout << "must be a positive number:" << endl;
			continue;
		}
		if (n % 2)
			cout << "odd number!" << endl;
		else
			cout << "even number!" << endl;
		cout << "pls input a number:" << endl;
	}
}

void practice_4_20()
{
	vector<string> vs{ "hello", "world", "!" };
	vector<string>::iterator vsi = vs.begin();

	cout << *vsi++ << endl;	//先执行自增操作,并返回自增前的副本,对其解引用
	//cout << (*vsi)++ << endl;	//错误:解引用后,进行自增运算,但 string 对象无法执行
	//if (*vsi.empty())	//错误, 解引用优先级低于点运算符,先尝试访问 vsi 的 empty 成员函数
	if (vsi->empty())	//相当于 (*vsi).empty()
		cout << "empty." << endl;
	else
		cout << *vsi << endl;
	//cout << ++*vsi << endl;	//错误:string 对象无法执行自增操作
	if (vsi++->empty())
		cout << "empty." << endl;
	else
		cout << *vsi << endl;

}

//在 vector<int> 中找出奇数并翻倍
void practice_4_21()
{
	vector<int> vi{4,1,5213,2,645,18,97,2,21,7,1,6764,2,843,6};
	for (auto &i : vi)
	{
		(i % 2) ? (i *= 2) : i;
		cout << i << endl;
	}
}

void practice_4_29()
{
	int x[10], *p = x;
	cout << sizeof(x) << endl;
	cout << sizeof(*x) << endl;
	cout << sizeof(x) / sizeof(*x) << endl;
	cout << sizeof(p) << endl;
	cout << sizeof(*p) << endl;
	cout << sizeof(p) / sizeof(*p) << endl;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值