小猪猪C++笔记基础篇(五)
关键词:表达式、语句
本章的内容比较简单,基本上没有什么理解上的困难,都是知识上的问题。先开始想要不要写呢,本来是不准备写的,但是既然读了书就要做笔记,还是写一写,毕竟还是有点点收获的东西。那么,我只就一些容易弄糊涂和忽略的地方提出来,为日后变成作参考。
一、表达式
(一)概念
表达式时由一个或者多个运算对象组成的,对一个表达式求值将得到一个结果。把一个运算发和一个或者多个运算对象组合起来可以生成较为复杂的表达式。
作用于一个对象的运算符是一元运算符例如:“&”,“*”等。运用于两个对象的运算符是二元运算符,例如“+”、“-”、“==”、“!=”等。
在C++中表达式要么是左值,要么是右值。左值可以位于赋值语句的左侧、右值不能。当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的史诗,用的是对象的身份(在内存中的位置)。我们熟悉的运算符都是要用到左值的。
使用关键则decltype的时候,我们根据左值右值的判断可以知道decltype得到的类型。如果表达式求值的结果是左值,decltype得到一个引用类型,如果表达式求值结果是右值,则得到一个指针类型。例如int *p;那么decltype(*p),*p是左值,得到的是int &引用,decltype(&p)得到的结果是指针,int**。
(二)一些值得注意的运算符
取负,一元符号运算是对象值取负后,返回其(提升后)的副本。要注意,无符号型的数和BOOL型的数不能做这样的运算。无符号型取负值会提升成有符号类型,如果没有溢出就相安无事,如果溢出了一般会发生“环绕”,跟第一章中间讲的溢出差不多的性质。布尔型的数据取负后会提升成int型,我们知道true=1,取负就成了-1。但是对于bool型是非0为true,0为false,所以取负以后还是true。
取模运算“%”,我们规定m%(-n)=m%n,(-m)%n=-(m%n)。简单的说,取模运算的符号是由前面那个数的符号决定的。所说,(-m)%(-n)=-(m%n)。
递增运算符(++)和递减运算符(--),即为对象加1和对象减1。这两种运算也可以用于不支持算数运算的迭代器。我们以递增运算符为例,递减运算符类似,分为前置版本++i,和后置版本i++。前置版本的意思是先对i加1再作为左值返回,后置版本是将对象的原始值的副本作为右值返回,再自加。
int i=0;
int j=i++;
cout<<i<<" "<<j<<endl;
j=++i;
cout<<i<<" "<<j<<endl;
第一个j=i++;是j赋值为i的原始值副本以后,i再自加。第二个++i,是i先自加以后再赋值给j。一般我们更习惯用++i而不采用i++。
另外,还要值得注意的是,++运算符的优先级是高于解引用运算符的。我们假设p是一个指针,那么*p++的意思是*(p++);把p的值加1,然后返回p的值的初试副本作为其求值结果,解引的值是没有自加后的结果。
int a[10];
int *p=a;
for(int i=0;i<10;++i)
a[i]=i;
for(int i=0;i<10;++i)
{
cout<<*p++<<" ";
}
条件运算符(?:), 这里有几个有趣的例子。
int grade=50;
cout<<((grade<60)?"fail":"pass");
cout<<(grade<60)?"fail":"pass";
cout<<grade<60?"fail":"pass";
第三条cout语句是编译都通不过的,前面两条是对的。我们输出结果看一看。
第一个输出的是(grade<60)?"fail":"pass"这个语句的值,第二个输出的是1,其实就是grade<60的值是true。所以当你不清楚优先级的时候最稳妥的方法就是打括号。
位移运算符(<<,>>),按照二进制移动,记住左移<<变大,右移>>变小,多的去掉。我们可以用位移运算符来处理类似于BOOL型的数组问题,这里不详述。另外我们熟悉的cout<<,cin>>这种重载版本的IO运算符,IO重载我们会在后面的章节详述,需要了解的是“cout<<”返回的还是一个cout,cin是一个道理。
Sizeof()运算符,是的它是一个运算符,不是一个函数,它的运算结果部分的依赖于作用的类型。对应用类型执行sizeof()得到的是被引用对象所占空间大小。对指针执行sizeof()运算得到的是指针本身所占的空间。我们可以用下面这种语句来求数组元素的个数:
int a[10]={0};
cout<<"sizeof(a):"<<sizeof(a)<<endl;
cout<<"sizeof(*a):"<<sizeof(*a)<<endl;
cout<<sizeof(a)/sizeof(*a)<<endl;
显示转化static_cast。可以消除强制类型转换的时候报WARNNING
把常量转化成变量:const_cast;
隐式的类型转换我们再第一章中已经说过了,不再赘述。
在我们编程的过程中基本上碰到的一些奇怪的操作符就是上面着一些的,如果你的表达式得到的结果并不是你想要的最好的方法就是多试几遍。
歇口气,喝口水。如果您觉得这些对您一点点帮助或者写的有些问题,可以给我留言,来鼓励鼓励我吧~如果想抱走的话希望能够引用我的链接~么么哒。
二、语句
语句就是我们基本说的条件语句、迭代语句什么的,平时都很常用,这里只对一些需要注意的点说明一下。
if-else语句,这种语句我们都很熟悉,唯一需要说明的是,在C++中规定else是跟最近的未匹配的if配对。
if(a) if(b) else c;
这里的else 是跟if(b)匹配的。不过建议还是用花括号来明确表示吧。
Switch(){case:}语句。Switch内部的变量必须是个常量且为整数,char,int,bool都可以,但是不能是浮点数。另外每一个case对应一个break,如果不写break的话,会接着做下一条case,且不用满足下一条case的条件,这个应该都很熟悉了;不能够跨case声明变量。也就是
case 1:int a;break;
case 2:a=3;break;
这样是不行的,原因可以参见一下变量的作用域问题。
跳转语句break,continue。作用于最近的循环语句。Break是跳出循环,continue是碰到了以后不再做下面的语句,直接进入下一次循环。下面一小段代码可以说明这个问题:
int a[10];
for(int i=0;i<10;++i)
{
a[i]=i*6-i*i;
cout<<a[i]<<" ";
}
cout<<endl;
for(int i=0;i<10;++i)
{
if(a[i]>7)break;
cout<<a[i]<<" ";
}
cout<<endl;
for(int i=0;i<10;i++)
{
if(a[i]>7)continue;
cout<<a[i]<<" ";
}
Break是碰到大于7的数就跳出循环了。而continue是不输出大于7的数。
另外还有goto语句,一般都不会用到它,它会造成一些混乱,但是有时候却有你意想不到的奇效,不过还是能不用尽量不用吧,这属于高难度动作啦。
最后还有抛出异常语句,简单的说一下就是try{一段程序,有问题我们就throw一个异常}然后用catch接住这个异常并且做相应的处理。对于程序的健壮性和安全性的处理是件很困难的事情,经验很重要。
如果有人看是我写下去的动力啦~当然没人不看我也会写的,因为知识和成长是自己的~~~