#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;
}
c++ primer(第五版)笔记 第四章 表达式
最新推荐文章于 2024-09-10 01:46:06 发布