指 针 和 引 用

一、  指针的概念

1.指针含义: 指针就是内存地址。

2.定义:

l         指针是一个变量,其内容为内存地址。

l         指针定义与其他普通变量类似,凡是声明变量的地方,就可声明指针变量。

l         指针变量只是分配了分配了存放地址的空间,但未具体将某个确切地址存入其中。

          类型 *指针名;

          类型:int,float,char,double……

3.建立指针:

               int *iptr,*iptr2;

     int a=180;      int b=120;

     iptr1=&a;        //iptr1的值就是a的地址。

     iptr2=&b;    iptr1=iptr2; 

4.  间接引用指针操作符:*

     b=*iptr1;

5.  指针变量的地址:

     int m=150;    int *ptr=&m;

     cout<<m<<endl; cout<<ptr<<endl;

     cout<<&m<<endl; cout<<*ptr<<endl;

     cout<<&ptr<<endl;

6.  指针的初始化:

定义时初始化

    运行时初始化

 

7.指针数组

l         指针的运算(+/-)是以指针的类型展开的。

l         数组名本身就是数组的起始地址。

l         数组名初始化指针:

     int a[20];

     int *ptr=a;   或 int *ptr=&a[20];   int *ptr=:a;

l         指针与数组的等价操作:

    a[i]=*(a+i)=ptr[i]=*(ptr+i);

    &a[i]=a+i=ptr+i=&ptr[i];

     注意:sizeof(a)与sizeof(*a)的区别!

l         数组名是指针常量----不是左值

 int a[200];

 a++;  //error!

二、  堆内存

 1.堆内存是程序运行时临时申请的内存空间,是动态空间。

2.malloc()与free()函数

void *malloc(size);

void *free(void *);

int *ptr;

ptr=(int *)malloc(1000);

free(ptr);

1.  new与delete操作符

l         new分配单个变量-----可提供初始值

          int *pi;

             pi=new int;      pi=new int(100);

l         new分配数组-----不能提供初始值

         new type[size];

             int *pi;        pi=new int[100];

l         分配多维数组:

指针p定义为:   type (*p)[m][n][s];

                     p=new type[size][m][n][s];

    其中,m,ns为整常数,size为整形表达式,该语句建立了有size个元素,

    每个元素类型为type[m][n][s]的数组,new 返回指向第一个元素的指针。

      delete p;

     new分配的地址不能改变,将用于delete的释放。

注意:申请内存后,一定要进行是否成功判断。一般申请不到时,返回空指针NULL。

      用完内存后,一定要释放所申请的空间。

例:

#include <iostream.h>

//#include <malloc.h>

void main()

{

  int arraysize;

  int *array;

  cout<<"input a number of array:/n";

  cin>>arraysize;

 

  array=new int[arraysize])

  if((array==NULL)

  {

    cout<<"can't allocate more memory, return./n";

    return;

  }

  for (int count=0;count<arraysize;count++)

  {

    array[count]=count*2;

    cout<<array[count]<<" ";

  }

  cout<<endl;

  delete[]array;

}

 

三、  const指针(了解)

1.  指向常量的指针

     const int  a=28;           const int   b=36;

     const int *pi=&a;

     pi=&b;  //OK!             *pi=56;  //error!

                      pi                                                              

      7800:0100(pi地址)7800:0120->7800:0120(b地址)36   

      pi指向的对象值不能被修改,pi本身可以被修改。

2.  指针常量

     指针前加上const

     int *const pi;

     pi本身不能被修改,pi指向的对象值可以被修改。

3.  指向常量的指针常量

     const  int a=5;

     const  int * const pi=&a;    //pi和*pi都不能被修改!         

四、  字符指针

1.  字符数组和字符串常量------常量指针

 字符串常量存放于data区的const区中。

     “chinachina, 两者是地址的比较,要用strcmp()比较!

2.  字符指针

     字符串常量,字符数组名,字符指针均属于同一数据类型!

     char *ptr=hello;

     cout<<ptr<<endl;               hello

     cout<<ptr+1<<endl;             ello

     cout<<*ptr<<endl;              h 

3.  字符串比较

l     两个字符串常量的比较是地址的比较,两个数组名的比较也是地址的比较。

l     字符串内容的比较函数

int strcmp(char *str1,char *str2);

int =0:   str1=str2;

>0:   str1>str2;

<0:   str1<str2;  

4.  字符串赋值

l     不能对字符数组赋一个字符串

l     char *strcpy(char *dest,char *src);

l     数值型数组的赋值函数

memcpy(int *ary1,int *ary2,int n_size);

五、  关于NULL指针和void指针

l         NULL是一个指针值,任何指针都可以赋予该值。

l         void 只表示一个地址,但不确定该地址起始的类型长度,void 不能运算。

l         void *是一种类型,是一种无任何类型的指针。

六、  指针与函数

1.   用指针给函数传递参数

     int i , j;

     void display( int * a , int *b );

    

     i=5;  j=10;

     display( &i , &j );

2.   传递数组给形参指针

      void sum1(int ary1[ ],int n); //编译器将int ary1[]解释为int *类型的指针

      void sum2(int *ary1 , int m);

     

      int a[10]={……};

    sum1(a,10);      sum2(a,10);

      void sort1( char c1[ ] , int i );

      void sort2( char *c2 , int j );

      char name[100]={……};      //等价于 char *name=”……”;

    sort1(name,100);

    sort2(name,100);

3.  返回指针的函数

可以返回堆地址,全局/静态变量地址,但不能返回局部变量地址!

int *fun()

{    int a[10];

return a;  }

        void main()

        {  int *p;

          p=fun();    }        //ERROR!

七、  命令行参数

       main()由操作系统调用,返回到操作系统。

       void main(int argc,char *argv[ ]);

       argc:指出命令行上的参数个数;

       argv:指针数组,其每个元素分别指向这些参数;

 

八.指针常用于以下情形:

1.函数参数

    用指针作为函数参数有两个好处:1)可以避免按值传递参数带来的空间浪费,2)可以通过指针间接修改形式参数所指向的地址空间。

2.字符串

   就是字符指针(和字符数组一样),字符串非常常用。

3.     动态空间申请  

    很多时候,要使用的内存空间在设计程序无法知道(如需要用户输入),需要在运行过程中,通过new来动态申请空间,new返回的就是指针。动态申请的空间可以是简单数据类型,也可以是数组、结构或是类等复杂数据类型。

4.  链表结构

    指针通常和结构一起使用,组成链表、树、图等各种复杂的数据结构。这些结构对于描述各种现实问题非常有用。

 

 

(二)引用

一、  引用的声明

类型   变量名;

类型 & 引用名;

exp:   int  a;   int &b=a;

1. 引用不是用作函数参数或返回值时,声明必须初始化。

2. 引用不是变量,对引用的存储都是对它引用的变量的存储。

3. 引用的初始化值必须是一个变量。

l             如果是对一个常量的引用,编译器要建立临时变量:

      const int num=50;

      int & ref=num;

      cout<<ref;      ref=ref+50;

      cout<<ref<<endl;      cout<<num<<endl;

l             如果声明的引用类型和初始化类型不一致,则编译器同样要建立和

     引用类型一致的变量:

 float real=50.3;

 int &ri=real;

 ri=ri+5;

 cout<<real<<end;    cout<<ri<<endl;

4. 不能声明引用的引用,也不能声明元素类型为引用的数组或指向引用的指针。

5. 可声明对指针的引用。

二、  引用参数

void fn(int &,float &);

l         效果同指针作参数一样,传递的是实参的地址,如果形参在fn()内发生改变,

    则实参也根着改变。

l         通过引用作参数,一个函数可以改变另一个函数内的变量。通过引用可以

    使一个函数返回多个值。

三、  返回引用的函数

#include<iostream.h>

float temp;

float fn1(float r)

   {  temp=r*r*3.14;  

      return temp;   }

float & fn2(float r)

   {  temp=r*r*3.14;

      return temp;  }

void main()

   {   float a=fn1(5.0);

       float &b=fn1(5.0);   //waring!

       float c=fn2(5.0); 

       float &d=fn2(5.0);

       cout<<a<<endl;     cout<<b<<endl;

       cout<<c<<endl;        cout<<d<<endl;

   }

四、  返回调用作左值

#include<iostream.h>

int a[ ]={2,4,6,8,10,12};

int& index(int i);

void main()

  {

      index(3)=16;

      cout<<index(3);               //out 16!

  }

int &index(int i)

  {   return a[i];  }

注意:返回引用的函数调用作左值时,不能返回函数内的自动变量;

   int & fun()

    {   int a; ……   return a;   }        //error!

五、  返回堆中变量的引用

int *ipt=new int;

if(ipt==NULL)

   {   cout<<error memory allocation !;  return 1;  }

int &IN_t=*ipt;

  

l         不能直接从堆中获得变量空间来初始化引用。

l         释放堆空间有两种方法:

     delete &IN_t;     delete  ipt;

六.引用总结:

    引用最大的作用就是作为函数的参数与返回值。

1.引用作为函数参数,有以下好处:

l         引用参数传递的就是实在参数本身,而不是实在参数的一个副本,这样减少了建立

    副本的消耗。

l         引用作为参数还可以作为函数返回值的一种有效途径。可以通过将引用定义为是

    const引用来限制在函数中对引用所代表的实在参数做修改。

2.引用作为返回值,有以下好处:

l         函数返回的是所返回的变量或对象本身,而不需要建立临时的对象。这样减少了程

    序运行的开销;

l         返回一个引用使得一个函数调用的表达式可以成为一个左值表达式,可以为其赋值。

5.  引用的作用和指针类似,但是它摆脱了使用指针可能带来的程序错误,也提高了程

   序的可读性和可理解性。推荐在能使用引用的地方尽量不要用指针。

七.有关函数调用的三种方法:

1.传值调用

#include<iostream.h>

void swap(int x,int y);

void main()

{

   int a=5,b=6;

   cout<<"a="<<a<<",b="<<b<<endl;

   swap(a,b);

   cout<<"a="<<a<<",b="<<b<<endl;

}

void swap(int x,int y)

{

   int temp=x;

   x=y;

   y=temp;

}

 

2.传址调用(用指针)

#include<iostream.h>

void swap(int *x,int *y);

void main()

{

  int a=5,b=6;

  cout<<"a="<<a<<",b="<<b<<endl;

  swap(&a,&b);

  cout<<"a="<<a<<",b="<<b<<endl;

}

void swap(int *x,int *y)

{

  int temp=*x;

  *x=*y;

  *y=temp;

}

 

3.传址调用(用引用)  // commented by mien , 这种方式同指针,也会改变原有变量得值

#include<iostream.h>

void swap(int &x,int &y);

void main()

{

  int a=5,b=6;

  cout<<"a="<<a<<",b="<<b<<endl;

  swap(a,b);

  cout<<"a="<<a<<",b="<<b<<endl;

}

void swap(int &x,int &y)

{

 

  int temp=x;

  x=y;

  y=temp;

}

定义抽象类 Shape 及其子类 Circle 和 Rectangle, 要求: (1) 抽象类 Shape 具有纯虚函数 Area(), 用于计算其子类的面积; (2) 抽象类 Shape 的子类 Circle、Rectangle, 覆盖父类的 Area() 方法, 用于计算各自的面积; (3) 通过 Shape 类分别向 Circle 对象、Rectagnle 对象, 并调用 Aera() 方法用于输出面积. 示例: #include <string> #include <iostream> #define _USE_MATH_DEFINES #include <math.h> class Shape { public: virtual double Area() = 0; }; class Circle: public Shape { public: Circle(double r); virtual double Area(); protected: double r; }; Circle::Circle(double r) { ... } double Circle::Area() { ... } 1 class Rectangle: public Shape { public: Rectangle(double w, double h); virtual double Area(); protected: double w; double h; }; Rectangle::Rectangle(double w, double h) { ... } double Rectangle::Area() { ... } int main() { std::cout << "-------------" << std::endl; std::cout << "创建Circel对象:" << std::endl; Circle circle(1); std::cout << " 面 积 为 :" << circle.Area() << std::endl; std::cout << "-------------" << std::endl; std::cout << "创建Rectangle对象:" << std::endl; Rectangle rect(2,2); std::cout << " 面 积 为 :" << rect.Area() << std::endl; Shape * pt; std::cout << "-------------" << std::endl; std::cout << "Shape 用 Circle 对 象 :" << std::endl; pt = &circle; std::cout << " 面 积 为 :" << pt->Area() << std::endl; std::cout << "-------------" << std::endl; std::cout << "Shape 用 Rectangle 对 象 :" << std::endl; pt = &rect; std::cout << " 面 积 为 :" << pt->Area() << std::endl; return 0; }
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值