c++笔记 ---表达式

1.  后自增操作的优先级高于解引用操作,因此 *iter++ 等效于  *(iter++)。 子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。 

2. 箭头操作符  (->)

下面的表达式相互等价:

(*p).foo; // dereference p to get an object and fetch its member named  foo  
p->foo;   // equivalent way to fetch the foo from the object to which  p points  

区别:

(*sp).same_isbn(item2); // run same_isbn on object to which sp points  

 这里,对 sp 进行解引用以获得指定的 Sales_item 对象。然后使用点操作符调用指定对象的 same_isbn 成员函数。在上述用法中,注意必须用圆括号把 解引用括起来,因为解引用的优先级低于点操作符。如果漏掉圆括号,则这段代码的含义就完全不同了:

  *sp.same_isbn(item2); // error: sp has no member named same_isbn  

 
这个表达式企图获得 sp 对象的 same_isbn 成员。等价于:  

*(sp.same_isbn(item2));  // equivalent to *sp.same_isbn(item2);  

 3. 条件操作符

1) 避免条件操作符的深度嵌套

2)在输出表达式中使用条件操作符

cout << (i < j ? i : j);  // ok: prints larger of i and j  
cout << (i < j) ? i : j;  // prints 1 or 0!  
cout << i < j ? i : j; // error: compares cout to int

 第二个表达式比较有趣:它将i和j 的比较结果视为 << 操作符的操作数,
输出 1 或 0。 << 操作符返回 cout 值,然后将返回结果作为条件操作符的判
断条件。也就是,第二个表达式等效于:  

cout << (i < j); // prints 1 or 0  
cout ? i : j;    // test cout and then evaluate i or j  
                      // depending on whether cout evaluates to true or  false  

 4.逗号运算符与逗号表达式

  • 逗号运算符:C++中,逗号既是分隔符,又是运算符,且优先级最低。
  • 逗号表达式:用逗号连接起来的表达式,其一般格式为:
        <表达式1>,<表达式2>,…,<表达式n>
  • 运算规则是:从左到右依次求出各表达式的值,并将最后一个表达式的值当做整个逗号表达式的值。


例如:假定a=1,b=2,c=3; 以下逗号表达式的结果是:

    c=b=(a=3,4*3) //结果为:a=3,b=12,c=12,表达式的值为12
    c=b=a=3,4*3  //结果为:a=3,b=3,c=3,表达式的值为12
    c=(b=a=3,4*3) //结果为:a=3,b=3,c=12,表达式的值为1

5.sizeof  操作符

sizeof有三种语法形式,如下:

1) sizeof( object ); // sizeof( 对象 );
2) sizeof( type_name ); // sizeof( 类型 );
3) sizeof object; // sizeof 对象;

 

所有指针变量的sizeof 操作结果均为4。

char、signed char和unsigned char的sizeof值为1

sizeof操作符,对变量或对象可以不加括号,但若是类型,须加括号。

sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:

sizeof( 2 ); // 2的类型为int,所以等价于 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof( double ); 

 sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用

函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错误的:

sizeof( foo ); // error

void foo2() { }
sizeof( foo2() ); // error

struct S
{
    unsigned int f1 : 1;
    unsigned int f2 : 5;
    unsigned int f3 : 12;
};
sizeof( S.f1 ); // error 

 


注意

1. int *p; sizeof(p)=4;     但sizeof(*p)相当于sizeof(int);      
      对于静态数组,sizeof可直接计算数组大小;
      例:

int a[10];char b[]="hello";
              sizeof(a)等于4*10=40;
              sizeof(b)等于6;

 

2. 数组做形参时,数组名称当作指针使用!!

 

 void  fun(char p[])
    {sizeof(p)等于4}    

 

 

3. 使用sizeof时string的注意事项
   string s="hello";
   sizeof(s)等于string类的大小,sizeof(s.c_str())得到的是字符串长度。

经典问题: 
      double* (*a)[3][6]; 
      cout<<sizeof(a)<<endl; // 4 a为指针
      cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组
      cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针
      cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针
      cout<<sizeof(****a)<<endl; // 8 ****a为一个double变量
问题解析:a是一个很奇怪的定义,他表示一个指向double*[3][6]类型数组的指针。既然是指针,所以sizeof(a)就是4。 
      既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)=3*6*sizeof(double*)=72。同样的,**a表示一个double*[6]类型的数组,所以sizeof(**a)=6*sizeof  (double*)=24。***a就表示其中的一个元素,也就是double*了,所以sizeof(***a)=4。至于****a,就是一个double了,所以sizeof(****a)=sizeof(double)=8

6.  new 和 delete 表达式

     动态创建对象时,只需指定其数据类型,而不必为该对象命名。取而代之的是,new 表达式返回指向新创建对象的指针,我们通过该指针来访问此对象:  

     int i;              // named, uninitialized int variable  
     int *pi = new int;  // pi points to dynamically allocated,  
                         // unnamed, uninitialized int  

   这个 new 表达式在自由存储区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针 pi。 

 

1>. 使用new动态分配内存:若没有足够内存,则new返回0(空值指针null pointer);
2>. 不要使用delete释放不是new分配的内存,delete释放指针指向的内存,但不会删除指针本身;
3>. 对空值指针应用delete是安全的;
4>. 一旦删除了指针所指向的对象,立即将指针置为 0,这样就非常清楚地表明指针不再指向任何对象。
5>. 创建数组时的静态联编动态联编:数组声名int a[10], 静态联编,数组的长度在编译时确定;
     用new[]创建数组,动态联编,运行时为数组分配内存空间。动态-运行时分配内存

 

动态创建对象的初始化

无论程序是明确地不初始化还是要求进行值初始化,都会自动调用其默认构造函数初始化该对象。而对于内置类型或没有定义默认构造 函数的类型,采用不同初始化方式则有显著的差别

int *pi = new int;         // pi points to an uninitialized int   240 
int *pi = new int();       // pi points to an int value-initialized  to 0  

 耗尽内存

如果程序用完了所有可用的内存,new 表达式就有可能失败。如果 new 表达式无法获取需要的内存空间,系统将抛出名为 bad_alloc 的异常

const 对象的动态分配和回收

下面三种常见的程序错误都与动态内存分配相关:  

    1. 删除( delete )指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间  后,耗尽了所有内存空间时,内存泄漏才会显露出来。  
   2. 读写已删除的对象。如果删除指针所指向的对象之后,将指针置为 0 值,则比较容易检测出这类错误。  
   3. 对同一个内存空间使用两次 delete 表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 delete 运算,将该对象的内存空间返还给自由存储区, 然后接着 delete 第二个指针,此时则自由存储区可能会被破坏。

删除 const 对象

不能改变 const 对象的值,但可撤销对象本身。如同其他动态
对象一样, const 动态对象也是使用删除指针来释放的

posted @ 2013-09-28 17:46  blue_whale  阅读(98)  评论(0)    收藏  举报