C++ primer chapter 4 数组与指针

==============================================================================

1  指针可能的取值:

     保存一个对象的地址。

     eg:

            int ival = 1024;

            int  *pi = &ival;   //指针pi(指向int类型的指针)   指向对象ival的地址。

 

     指向某个对象后面的另一个对象。

     eg:

           int    *pa = 0;      //指向int型的指针pa 未指向任何地方,初始化为0.

           int     ival = 1024;

           int    *pi   = &ival; // 同上例。

           pa = pi;                  // 现在pa 和 pi 指向同一个对象:ival。这样pa 就指向了

                                                 对象(指针 pi) 后的另一个对象(ival).

 

      指针取0值。

      eg:

           int   *pb = 0;       //pb 指针被初始化为0,没有指向任何地方。

 

建议:

除非指针所指向的对象已经存在了,否则不要先定义指针。

如果要分开定义指针和及其所指向的对象,就将该指针初始化为0.

==============================================================================

2 指针的初始化和赋值操作:(只能取以下4种类型的值)

    0值常量表达式:

    即在编译时可获得0值的int 型 const 对象    or      字面值常量0.

    所谓常量表达式,就是编译器在编译时,就能够计算出结果的整型表达式。

    eg:

           int                   *pi = 0;

           const int   c_ival = 0;

           pi       =      c_ival;

 

     类型匹配的对象的地址:

     eg :

            double dval;

            double *pd  =  &dval;         //OK:指针pd 指向的是double类型,与dval的类型匹配。

            int          *pi   =  0;

                            pi   =  &dval;         //ERROR: pi 指向的是int 类型,与dval的类型不匹配。

 

      另一个对象之后的下一地址 和 同类型的另一个有效指针:

       eg:

            double  dval;

            double  *pd  =  &dval;

            double  *pd2 = pd;

==============================================================================

3  void* 指针

    void* 指针特殊之处在于,它可以保存任何类型对象的地址。

    eg:

         double obj = 3.14;              //定义了一个double 类型的对象obj ,初始化为3.14

         double *pd = &obj;             //定义了一个指向double类型的指针pd,指向obj的地址。

         void      *pv = &obj;            //OK:因为是void* 型。

         pv                = pd;                //同上。

    注意:不允许void*指针操纵它指向的对象。

==============================================================================

4  指针操作

    对指针进行解引用可以访问它所指的对象。

    eg:

         string s("hello world");

         string *sp = &s;

         cout << *sp;                          //打印出hello world.

    下面修改指针所指向的值:

     eg:

          *sp = "ByeBye";

           cout<<*sp;                         //这样就不再打印hello world ,而变成ByeBye.

     修改指针所指向的对象:

     eg:

          string new_s = “I love you";

          sp = &new_s;

          cout<<*sp;                          //修改了sp所指向的对象,现在变成了I love you。

 

    关键:

    如果有解引用操作,那么就是修改指针所指向的对象;如果没有,就是修改指针本身。

============================================================================= 

5 指针和引用的区别

    有2个区别:第一个是引用总是指向某个对象,定义 引用的时候 如果没有初始化那就是错误的。

    第二个区别:(很重要)

    给引用赋值修改的是: 它所关联的对象的值,而不是让它去与另一个对象相关联。这是与指针最主要的差别。

    eg:

           int ival =1024,  ival2 = 2048;

           int *pi   =&ival,  *pi2  =  &ival2;

           pi  =  pi2;                                        //对于指针,赋值完成后,pi 所指向的对象ival的值保持不变,只是让pi 指向了另一个对象ival2.

    eg:

          int &ri = ival, &ri2 = ival2;

          ri  =  ri2;                                          //对于引用,赋值完成后,修改了ri引用的对象ival的值。但ri 和 ri2 所指向的对象仍然不变。

=============================================================================

6  指向指针的指针

     指针本身,也可以是其他指针指向的内存对象。所以一个指针的地址也可以存放在其他指针中。

     eg:

          int  ival  =  1024;

          int  *pi    =  &ival;                           //指针pi  指向Ival

          int  **ppi =  π                             //二级指针ppi 指向指针pi

          cout << **ppi;                                //进行2次解引用就可以访问到 ival

=============================================================================

7  使用指针访问数组元素

     在C++中,在表达式中使用数组名时,该数组名会自动转换为指向数组第一个元素的指针。

      eg:

           int   ia[]  =  {0,2,4,6,8};

           int   *ip  =   ia;                               //这样就使得ip指向ia数组的第一个元素ia[0];

           ip           =   &ia[4];                        //使用下标操作,可以给元素定位,通过地址操作符获取该元素的存储地址。

      也可以通过指针的 算数操作来获取指定内容的存储地址。

      eg:

           ip                   =    ia;                      //指针ip 指向ia[0]

           int     *ip2      =    ip + 4;               //指针ip2指向 ia[4]

 

    只要2个指针指向同一数组,C++还支持对着脸个指针进行减法操作:

     eg:

          ptrdiff_t    n    =   ip2 - ip;

     这里出现了一个新的数据类型,ptrdiff_t。它与size_t一样,都是机器相关的类型,定义在cstddef头文件中。

     size_t  是unsigned 型,ptrdiff_t是signed int 型。

 

     解引用和指针算术操作之间的相互作用。

     eg:

          int last   =    *(ia+4);                       //这样就获取了ia数组的最后一个元素。

     注意,这里的括号是必须的,因为* 的优先级大于 + 号。

 

     在数组中,用指针来模拟vector类型的begin()和end()函数。

      eg:

           const size_t  arr_size  =  5;

           int            arr[arr_size]  =  {1,2,3,4,5};

 

           int                               *p = arr;                           //p指向数组arr的第一个元素arr[0]

           int                             *p2 = p + arr_size;          //p2指向数组末尾的后一位。

      在C++中,允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作。

      现在来模拟vector的begin() 和 end():

      eg:

           const size_t  arr_sz  =  5;

           int      int_arr[arr_sz]  = {0,1,2,3,4};

           for(int  *pbegin = int_arr, *pend = int_arr+arr_sz; pbegin !=pend; pbegin++)

           {

                  cout<< *pbegin<<'    ' ;

            }

       pend类似与哨兵的作用。

==============================================================================

8  指针与const 限定符

     讨论2种指针:指向const对象的指针   and   const指针。

     对于第一种,指向const对象的指针:

     如果指针指向const对象,那么就不允许用指针来改变它所指向的const值。所以,C++强制要求指向const对象的指针

     也必须具备const特性!

     eg:

          const  double  *cptr;           //指针cptr指向一个double类型,const对象。

     注意,这里只是说,cptr所指的对象是const类型的,而cptr本身不是const类型。在定义时,不需要对cptr进行初始化。

     只允许让cptr 指向另一个const对象,不允许通过cptr 修改它所指对象的值。

     eg:

         *cptr =42; 这就是错误的,因为cptr是一个指向const对象的指针。

     相应的,把一个const 对象的地址,赋给普通的指针,也是错误的(所以说const变量 与 指向const对象的指针是一一对应的)

     eg:

           const double     pi = 3.14;          //const 变量 pi,为double 类型

           double             *ptr = π            //ERROR

           const double *cptr = π           //OK

     对于void* 指针,对于要保存const 对象的地址,也必须使用const void*类型。

     eg:

          const  int  universe  = 42;

          const  void      *cpv  =  &universe;      //OK

          void                  *pv    =  &universe;      //ERROR

      注意,允许把非const 对象的地址赋值给 指向const对象的指针。

      eg:

             double dval  = 3.14;                             //非const 对象 dval

             const double *cptr;                               //指向const对象的指针 cptr

             cptr                 =  &dval;                         //OK, 但是不能通过cptr 来修改dval的值。

      注:不能使用指向const对象的指针来修改基础对象,但如果该指针指向一个非const对象,可以用其他方法改变它所指的对象。

      eg:

           double              dval  = 3.14159;

           const  double  *cptr  = &dval;

           double              *ptr    = &dval;

                                      *ptr    = 2.72;

           cout<<*cptr;                                           // 2.72

      该例子说明,虽然无法直接通过cptr 来修改dval 的值,但可以通过一个普通指针进行转换,达到修改的目的。

      在实际应用中,指向const对象的指针常常作为形式参数,将形参定义为指向const对象的指针,可以确保传递给函数的实际对象,不会

      因为形式参数的修改而修改。

 

      对于第二种:const指针:

      C++ 提供const指针,该指针本身的值不能被修改。

      eg:

           int  errNumb  =  0;

           int  *const  curErr  = &errNumb;

      上面这句话,可以读作:curErr 是指向int型对象的const 指针。

      const指针的值不能修改,不能使curErr指向其他对象。const指针必须在定义时初始化。(我觉得很像引用)

      与指向const对象的指针不同的是,const 指针可以通过解引用操作,修改它所指对象的值。

     eg:

          *const curErr =  1;                              //OK

 

     拓展:指向const对象的const指针

     eg:

          const   double                       pi  =  3.14159;

          const   double  *const   pi_ptr  =  π

     这里的pi_ptr 既不能修改它所指对象的值,也不允许修改它的指向。

     可以读作: pi_ptr  是一个const 指针,指向double类型const 对象。(感觉没啥用,就是比较绕)。

===============================================================================

9.  指针与typedef 

      eg:

           typedef    string      *pstring;

           const      pstring     cstr;

      问:cstr 是什么类型? 很多人认为,cstr是一种指针,指向string类型的const对象。

              即const string *cstr(我也是这么认为的)但这是错误的。

      原因如下:

      误将typedef 当作文本扩展了。

      声明const pstring时,const 修饰的是pstring 类型。所以说,该声明语句应该是把cstr 定义为指向string 类型对象的const 指针。

      即:

             string *const cstr;

      所以好的建议就是,在用typedef 写 const 类型定义的时候,将const 限定符放在类型名之后,就不会产生混淆了。

      eg:

           string  s;

           typedef  string  *pstring ;

           pstring   const  cstr2 = &s;

       这样就很容易理解 cstr2 的类型了,即:指向string 对象的const 指针。

===============================================================================

 

 

你可能感兴趣的:(C++,和,设计模式)