C++指针学习建议.docx

上传人:b****7 文档编号:9578343 上传时间:2023-02-05 格式:DOCX 页数:36 大小:39.31KB
下载 相关 举报
C++指针学习建议.docx_第1页
第1页 / 共36页
C++指针学习建议.docx_第2页
第2页 / 共36页
C++指针学习建议.docx_第3页
第3页 / 共36页
C++指针学习建议.docx_第4页
第4页 / 共36页
C++指针学习建议.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

C++指针学习建议.docx

《C++指针学习建议.docx》由会员分享,可在线阅读,更多相关《C++指针学习建议.docx(36页珍藏版)》请在冰豆网上搜索。

C++指针学习建议.docx

C++指针学习建议

一.对于众多人提出的c/c++中指针难学的问题做个总结:

  指针学习不好关键是概念不清造成的,说的简单点就是书没有认真看,指针的学习犹如人在学习饶口令不多看多学多练是不行的,下面是两个很经典的例子,很多书上都有,对于学习的重点在于理解*x和x的理解,他们并不相同,*x所表示的其实就是变量a本身,x表示的是变量a在内存中的地址,如果想明白可以输出观察cout<<*x"|"x;,当定义了int*x;后对x=&a的理解的问题。

仔细阅读和联系下面的两个例子我想指针问题就不是难点了!

#include   

main() 

int a,b; /* 定义a,b两个整形变量用于输入两个整数 */

int *point_1,*point_2,*temp_point; /* 定义三个指针变量 */

scanf("%d,%d",&a,&b); /* 格式化输入a,b的值 */

point_1=&a; /* 把指针变量point_1的值指向变量a的地址 */

point_2=&b; /* 把指针变量point_2的值指向变量b的地址 */

if (a

    temp_point=point_1; /* 这里的temp_point是用于临时存储point_1的值也就是变量a的地址的 */

    point_1=point_2; /* 把point_2的值赋予point_1 */

    point_2=temp_point; 

    /* 由于point_1的值已经改变无法找到,利用前面临时存储的也就是temp_point找回原point_1的值赋予point_2,打到把point_1和point_2值对换的目的*/

printf("%d,%d",*point_1,*point_2); /* 利用*point_1和*point_2也就是分辨指向b和a的方法把值显示屏幕上 */

}  

/* 此题需要注意和了解是的此法并没有改变变量a,b的值只是利用指针变量分别存储a和b的地址,然后再把那两个指针变量的值对换一下其实就是存储在指针变量里面a与b的地址对换,在利用*point_1和*point_2的方式把调换后的值显示出来这里的*point_1实际就是a,此中算法并非真的改变a,b的值,而是利用指针进行地址交换达到大小排序的目的. */

#include  

main() 

int a,b; /* 定义a,b两个整形变量用于输入两个整数 */

int *point_1,*point_2; /* 定义三个指针变量 */

scanf("%d,%d",&a,&b); /* 格式化输入a,b的值 */

point_1 = &a; /* 把指针变量point_1的值指向变量a的地址 */

point_2 = &b; /* 把指针变量point_2的值指向变量b的地址 */

compositor(point_1,point_2); /* 调用自定义的排序涵数,把a,b的地址传递给point_1和point_2 */

printf("%d,%d",a,b); /* 打印出a,b的值 */

static compositor(p1,p2) 

int *p1,*p2; /* 定义形式参数p1,p2为指针变量 */

int temp; /* 建立临时存储变量 */

    if (*p1<*p2) /* 如果*p1

    { 

        temp = *p1; /* 利用变量temp用于临时存储*p1和就是a的值 */

        *p1 = *p2; /* 将*p1的值也就是a的值换成*p2的值也就是b的值,等价于a=b */

        *p2 = temp; /* 将*p2的值也就是temp的值等价于b=temp */

    } 

}  

/* 注意:

此题与上题不同的是,直接改变了a于b的值达到真实改变的目的 */

二.C++指针使用方法解惑

“voidClearList(LNode*&HL)”

仔细看一下这种声明方式,确实有点让人迷惑。

下面以voidfunc1(MYCLASS*&pBuildingElement);为例来说明这个问题。

在某种意义上,"*"和"&"是意思相对的两个东西,把它们放在一起有什么意义呢?

为了理解指针的这种做法,我们先复习一下C/C++编程中无所不在的指针概念。

我们都知道MYCLASS*的意思:

指向某个对象的指针,此对象的类型为MYCLASS。

Voidfunc1(MYCLASS*pMyClass);

//例如:

MYCLASS*p=newMYCLASS;

func1(p);

上面这段代码的这种处理方法想必谁都用过,创建一个MYCLASS对象,然后将它传入func1函数。

现在假设此函数要修改pMyClass:

voidfunc1(MYCLASS*pMyClass)

{

DoSomething(pMyClass);

pMyClass=//其它对象的指针

}

  第二条语句在函数过程中只修改了pMyClass的值。

并没有修改调用者的变量p的值。

如果p指向某个位于地址0x008a00的对象,当func1返回时,它仍然指向这个特定的对象。

(除非func1有bug将堆弄乱了,完全有这种可能。

  现在假设你想要在func1中修改p的值。

这是你的权利。

调用者传入一个指针,然后函数给这个指针赋值。

以往一般都是传双指针,即指针的指针,例如,CMyClass**。

MYCLASS*p=NULL;

func1(&p);

voidfunc1(MYCLASS**pMyClass);

{

*pMyClass=newMYCLASS;

……

}

  调用func1之后,p指向新的对象。

在COM编程中,你到处都会碰到这样的用法--例如在查询对象接口的QueryInterface函数中:

interfaceISomeInterface{

HRESULTQueryInterface(IID&iid,void**ppvObj);

……

};

LPSOMEINTERFACEp=NULL;

pOb->QueryInterface(IID_SOMEINTERFACE,&p);

  此处,p是SOMEINTERFACE类型的指针,所以&p便是指针的指针,在QueryInterface返回的时候,如果调用成功,则变量p包含一个指向新的接口的指针。

如果你理解指针的指针,那么你肯定就理解指针引用,因为它们完全是一回事。

如果你象下面这样声明函数:

voidfunc1(MYCLASS*&pMyClass);

{

pMyClass=newMYCLASS;

……

}

其实,它和前面所讲得指针的指针例子是一码事,只是语法有所不同。

传递的时候不用传p的地址&p,而是直接传p本身:

  MYCLASS*p=NULL;

  func1(p);

  在调用之后,p指向一个新的对象。

一般来讲,引用的原理或多或少就象一个指针,从语法上看它就是一个普通变量。

所以只要你碰到*&,就应该想到**。

也就是说这个函数修改或可能修改调用者的指针,而调用者象普通变量一样传递这个指针,不使用地址操作符&。

  至于说什么场合要使用这种方法,我会说,极少。

MFC在其集合类中用到了它--例如,CObList,它是一个Cobjects指针列表。

 

ClassCObList:

publicCobject{

……

//获取/修改指定位置的元素

Cobject*&GetAt(POSITIONposition);

Cobject*GetAt(POSITIONposition)const;

};

  这里有两个GetAt函数,功能都是获取给定位置的元素。

区别何在呢?

  区别在于一个让你修改列表中的对象,另一个则不行。

所以如果你写成下面这样:

Cobject*pObj=mylist.GetAt(pos);

  则pObj是列表中某个对象的指针,如果接着改变pObj的值:

pObj=pSomeOtherObj;

  这并改变不了在位置pos处的对象地址,而仅仅是改变了变量pObj。

但是,如果你写成下面这样:

Cobject*&rpObj=mylist.GetAt(pos);

  现在,rpObj是引用一个列表中的对象的指针,所以当改变rpObj时,也会改变列表中位置pos处的对象地址--换句话说,替代了这个对象。

这就是为什么CObList会有两个GetAt函数的缘故。

一个可以修改指针的值,另一个则不能。

注意我在此说的是指针,不是对象本身。

这两个函数都可以修改对象,但只有*&版本可以替代对象。

在C/C++中引用是很重要的,同时也是高效的处理手段。

所以要想成为C/C++高手,对引用的概念没有透彻的理解和熟练的应用是不行的。

三.数据指针

在C/C++语言中一直是很受宠的;几乎找不到一个不使用指针的C/C++应用。

用于存储数据和程序的地址,这是指针的基本功能。

用于指向整型数,用整数指针(int*);指向浮点数用浮点数指针(float*);指向结构,用对应的结构指针(structxxx*);指向任意地址,用无类型指针(void*)。

   有时候,我们需要一些通用的指针。

在C语言当中,(void*)可以代表一切;但是在C++中,我们还有一些比较特殊的指针,无法用(void*)来表示。

事实上,在C++中,想找到一个通用的指针,特别是通用的函数指针简直是一个“不可能任务”。

   

   C++是一种静态类型的语言,类型安全在C++中举足轻重。

在C语言中,你可以用void*来指向一切;但在C++中,void*并不能指向一切,就算能,也失去了类型安全的意义了。

类型安全往往能帮我们找出程序中潜在的一些BUG。

   

   下面我们来探讨一下,C++中如何存储各种类型数据的指针。

C++指针探讨

(一)数据指针    沐枫网志

   

   1. 数据指针

    数据指针分为两种:

常规数据指针和成员数据指针

    

   1.1常规数据指针

    这个不用说明了,和C语言一样,定义、赋值是很简单明了的。

常见的有:

int*,double*等等。

    如:

     int value = 123;

     int * pn = &value;

       

   1.2成员数据指针

    有如下的结构:

     struct MyStruct

     {

       int key;

       int value;

     };

   

    现在有一个结构对象:

     MyStruct me;

    MyStruct*pMe=&me;

   

    我们需要value成员的地址,我们可以:

     int * pValue = &me.value;

    //或

    int *pValue=&pMe->value;

   

    当然了,这个指针仍然是属于第一种范筹----常规数据指针。

    

    好了,我们现在需要一种指针,它指向MyStruct中的任一数据成员,那么它应该是这样的子:

     int MyStruct:

:

* pMV = &MyStruct:

:

value;

     //或

     int MyStruct:

:

* pMK = &MyStruct:

:

key;

   

    这种指针的用途是用于取得结构成员在结构内的地址。

我们可以通过该指针来访问成员数据:

     int value = pMe->*pMV; // 取得pMe的value成员数据。

     intkey= me.*pMK; // 取得me的key成员数据。

   

    那么,在什么场合下会使用到成员数据指针呢?

   确实,成员指针本来就不是一种很常用的指针。

不过,在某些时候还是很有用处的。

我们先来看看下面的一个函数:

  int sum(MyStruct*objs, int MyStruct:

:

* pm, int count)

  {

      int result = 0;

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

          result += objs[i].*pm;

      return result;

  }

    这个函数的功能是什么,你能看明白吗?

它的功能就是,给定count个MyStruct结构的指针,计算出给定成员数据的总和。

有点拗口对吧?

看看下面的程序,你也许就明白了:

    

     MyStruct me[10] =

     {

      {1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}

     };     

     int sum_value = sum(me, &MyStruct:

:

value, 10);

     //计算10个MyStruct结构的value成员的总和:

 sum_value 值 为 110     (2+4+6+8+

+20)

     int sum_key = sum(me, &MyStruct:

:

key, 10);

   //计算10个MyStruct结构的key成员的总和:

   sum_key 值 为 100       (1+3+5+7+

+19)

    也许,你觉得用常规指针也可以做到,而且更易懂。

Ok,没问题:

     int sum(MyStruct*objs, int count)

     {

      int result = 0;

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

       result += objs[i].value;

      return result;

     }

你是想这么做吗?

但这么做,你只能计算value,如果要算key的话,你要多写一个函数。

有多少个成员需要计算的话,你就要写多少个函数,多麻烦啊。

指针

四.C++指针使用

在下列函数声明中,为什么要同时使用*和&符号?

以及什么场合使用这种声明方式?

  

voidfunc1(MYCLASS*&pBuildingElement); 论坛中经常有人问到这样的问题。

 本文试图通过一些实际的指针使用经验来解释这个问题。

 

仔细看一下这种声明方式,确实有点让人迷惑。

在某种意义上,"*"和"&"是意思相对的两个东西,把它们放在一起有什么意义呢?

为了理解指针的这种做法,我们先复习一下C/C++编程中无所不在的指针概念。

我们都知道MYCLASS*的意思:

指向某个对象的指针,此对象的类型为MYCLASS。

voidfunc1(MYCLASS*pMyClass);  

//例如:

MYCLASS*p=newMYCLASS; 

func1(p); 

上面这段代码的这种处理方法想必谁都用过,创建一个MYCLASS对象,然后将它传入func1函数。

现在假设此函数要修改pMyClass:

voidfunc1(MYCLASS*pMyClass) 

DoSomething(pMyClass); 

pMyClass=//其它对象的指针 

}  

第二条语句在函数过程中只修改了pMyClass的值。

并没有修改调用者的变量p的值。

如果p指向某个位于地址0x008a00的对象,当func1返回时,它仍然指向这个特定的对象。

(除非func1有bug将堆弄乱了,完全有这种可能。

) 

现在假设你想要在func1中修改p的值。

这是你的权利。

调用者传入一个指针,然后函数给这个指针赋值。

以往一般都是传双指针,即指针的指针,例如,CMyClass**。

MYCLASS*p=NULL; 

func1(&p); 

voidfunc1(MYCLASS**pMyClass); 

*pMyClass=newMYCLASS; 

…… 

调用func1之后,p指向新的对象。

在COM编程中,你到处都会碰到这样的用法--例如在查询对象接口的QueryInterface函数中:

 

interfaceISomeInterface{ 

HRESULTQueryInterface(IID&iid,void**ppvObj); 

…… 

}; 

LPSOMEINTERFACEp=NULL; 

pOb->QueryInterface(IID_SOMEINTERFACE,&p); 

此处,p是SOMEINTERFACE类型的指针,所以&p便是指针的指针,在QueryInterface返回的时候,如果调用成功,则变量p包含一个指向新的接口的指针。

 

如果你理解指针的指针,那么你肯定就理解指针引用,因为它们完全是一回事。

如果你象下面这样声明函数:

 

voidfunc1(MYCLASS*&pMyClass); 

pMyClass=newMYCLASS; 

…… 

其实,它和前面所讲得指针的指针例子是一码事,只是语法有所不同。

传递的时候不用传p的地址&p,而是直接传p本身:

 

MYCLASS*p=NULL; 

func1(p); 

在调用之后,p指向一个新的对象。

一般来讲,引用的原理或多或少就象一个指针,从语法上看它就是一个普通变量。

所以只要你碰到*&,就应该想到**。

也就是说这个函数修改或可能修改调用者的指针,而调用者象普通变量一样传递这个指针,不使用地址操作符&。

 

至于说什么场合要使用这种方法,我会说,极少。

MFC在其集合类中用到了它--例如,CObList,它是一个CObjects指针列表。

 

classCObList:

publicCObject{ 

…… 

//获取/修改指定位置的元素 

CObject*&GetAt(POSITIONposition); 

CObject*GetAt(POSITIONposition)const; 

}; 

这里有两个GetAt函数,功能都是获取给定位置的元素。

区别何在呢?

 

区别在于一个让你修改列表中的对象,另一个则不行。

所以如果你写成下面这样:

CObject*pObj=mylist.GetAt(pos); 

则pObj是列表中某个对象的指针,如果接着改变pObj的值:

pObj=pSomeOtherObj; 

这并改变不了在位置pos处的对象地址,而仅仅是改变了变量pObj。

但是,如果你写成下面这样:

CObject*&rpObj=mylist.GetAt(pos); 

现在,rpObj是引用一个列表中的对象的指针,所以当改变rpObj时,也会改变列表中位置pos处的对象地址--换句话说,替代了这个对象。

这就是为什么CObList会有两个GetAt函数的缘故。

一个可以修改指针的值,另一个则不能。

注意我在此说的是指针,不是对象本身。

这两个函数都可以修改对象,但只有*&版本可以替代对象。

 

在C/C++中引用是很重要的,同时也是高效的处理手段。

所以要想成为C/C++高手,对引用的概念没有透彻的理解和熟练的应用是不行的。

五.新手学习之浅析c/c++中的指针

在学习c/c+过程中,指针是一个比较让人头痛的问题,稍微不注意将会是程序编译无法通过,甚至造成死机。

在程序设计过程中,指针也往往是产生隐含bug的原因。

下面就来谈谈指针的应用以及需要注意的一些问题,里面也许就有你平时没有注意到的问题,希望能帮助各位读者理解好指针。

  一、我们先来回忆一下指针的概念吧,方便下面的介绍

  指针是存放地址值的变量或者常量。

例如:

inta=1;&a就表示指针常量(“&”表示取地址运算符,也即引用)。

int*b,b表示的是指针变量(注意,是b表示指针变量而不是*b),*表示要说明的是指针变量。

大家注意int*b[2]和int(*b)[2]是不同的,int*b表示一个指针数组,而int(*b)[2]表示含有两个元素的int指针,这里要注意运算优先级问题,有助于理解指针问题。

在这里大概介绍基本概念就够了,至于具体使用方法,如赋值等,很多书都有介绍,我就不多说了。

  

  二、应用以及注意的问题

  1、理解指针的关键所在——对指针类型和指针所指向的类型的理解

  ①、指针类型:

可以把指针名字去掉,剩下的就是这个指针

  例如:

int*a;//指针类型为int*

    int**a;//指针类型为int**  

  int*(*a)[8];//指针类型为int*(*)[8]  

  ②、指针所指向的类型:

是指编译器将把那一片内存所看待成的类型。

这里只要把指针声明语句中的指针名字和名字右边的“*”号去掉就可以了,剩下的就是指针所指向的类型。

  

  我之所以把他们放在第一位,是因为弄清楚他们是学c/c++指针的重点,正确理解他们才能使你打好c/c++的编程基础。

  

  2、指针的应用——传递参数。

  其实它可以相当于隐式的返回值,这就比return的方法更加灵活了,可以返回更多的值,看看下面的例子自然就明白了:

  #include"iostream.h"

  voidexample(int*a1,int&b1,intc1)

  {

   *a1*=3;

   ++b1;

   ++c1;

  }

  voidmain()

  {

   int*a;

   intb,c;

   *a=6;

   b=7;c=10;

   example(a,b,c);

   cout<<"*a="<<*a<

   cout<<"b="<

   cout<<"c="<

  }

  输出:

*a=18

  b=8

  c=10

  注意到没有,*a和b的值都改变了,而c没有变。

这是由于a1是指向*a(=6)的指针,也即与a是指向同一个地址,所以当a1指向的值改变了,*a的值也就改变了。

在函数中的参数使用了引用(int&b1),b1是b的别名,也可以把它当作特殊的指针来理解,所以b的值会改变。

函数中的参数intc1只是在函数中起作用,当函数结束时候便消失了,所以在main()中不起作用。

  

  3、关于全局变量和局部变量的一个问题先不废话了,先看看程序:

  #include“iostream.h”

  inta=5;

  int*example1(intb)

  {

  a+=b;

  return&a;

  }

  int*example2(intb)

  {

  intc=5;

  b+=c;

  return&b;

  }

  voidmain()

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1