指针

1.指针的概念:指针是存储内存地址的变量,指向一个数据结构的首地址。

2.指针的内存大小只有四个字节。

3.三种声明指针类型的方式:类型名  *变量名;类型名*  变量名;类型名  *  变量名;

4.一次定义多个指针变量,每个指针变量前必须加“*”,否则,只有前面加“*”的才能被解释成指针。

5.给指针变量赋值时需要注意:1)未经赋值的指针变量不能使用。2)指针变量的赋值只能赋予地址, 决不能赋予任何其它数据。

6.给指针赋值的六种方式:


7.NULL是一个指针常量,表示空地址。当指针变量暂时无法确定其指向或暂时不用时,可以将它指向空地址,以保证程序的正常运行。

8.指针的运算:指针加上或减去一个整数n,表示指针从当前位置向后或向前移动n*sizeof<数据类型>大小的地址空间。

9.两个指针相减:当两个指针指向同一数组时,两个指针的相减才有意义,两个指针相减的结果是一个整数,表示两个指针之间数组元素的个数。

10.两个指针的比较运算:

pf1==pf2 表示pf1pf2指向同一数组元素;

pf1>pf2 表示pf1处于高地址位置;

pf1<pf2 表示pf1处于低地址位置。

11.指针变量为0和指针变量未赋值是不同的概念。

12.无类型指针(void类型的指针):可以指向任何类型的数据,但是无类型的指针不能进行"解引用"操作。只包含一个信息:首地址。可以强制转换成任何类型的指针。

13.代码如下:

#include <iostream>

using namespace std;

//---2015.4.20指针---

//指针变量的定义格式:

//  数据类型 * 指针变量名 = NULL;

int add(int a ,int b)

{

return a+b;

}

void main()

{

//指针类型是在其他数据类型基础上演变而来,

//"什么类型的指针指向什么类型的数据"

 

//指针变量定义中的*号,它的作用是:定义指针变量

// &号:取地址运算符

char * pChar=NULL;//字符型指针

char cValue = 'W'; //字符型变量

pChar = &cValue; //让pChar指向cValue

//指针的使用:

cout<<"通过变量名访问该变量的首地址:"<<&cValue<<endl;

cout<<"通过指向该变量的指针访问该变量的首地址:"<<pChar<<endl;

bool * pBool = NULL;

bool bValue = true;

pBool = &bValue;

cout<<"通过变量名访问该变量的首地址:"<<&bValue<<endl;

cout<<"通过指向该变量的指针访问该变量的首地址:"<<pBool<<endl;

short sValue = 200;

short * pShort1 = &sValue;

short * pShort2 = pShort1;

short * pShort3 = &sValue;

cout<<"----"<<*pShort2<<endl;

int iValue1 = 1111111113 , iValue2 = 5;

//看上去,像是声明2个int型指针,但实际上是声明了

//一个整型指针p1,一个整型变量p2

int * p1 , p2;

//正确定义两个整型指针的方式:

int * p3 = NULL , * p4 = NULL;

//------无类型指针--------

//特点:可以指向任何类型的数据,但是无类型的指针

//   不能进行"解引用"操作。

void * pVoid = NULL ;

pVoid = &cValue;

pVoid = &bValue;

pVoid = &sValue;

pVoid = &iValue1;

//cout<<*pVoid<<endl;//反例:不能对无类型的指针进行解引用

cout<<"------------"<<*((int*)pVoid)<<endl;

//将数组的首地址赋给指针型变量

int iArray[10] = {1,2,3,4,5,6,7,8,9};

int * pArray = iArray;

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

cout<<iArray[i]<<endl;

//当一个指针指向一个数组的时候,

//可以通过指针直接访问数组元素

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

cout<<pArray[i]<<endl;

//另外一种通过指针访问数组元素的方式:

cout<<"--------------------"<<endl;

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

{

//利用指针的偏移访问数组元素

cout<< *(pArray+i) <<endl;

}

cout<<"--------------------"<<endl;

char * pStr = "HelloWorld";

cout<<pStr<<endl;

//---函数指针---

int (*pFunc)(int,int) = NULL;

pFunc = add;

cout<<add(3,5)<<endl;

cout<<pFunc(30,40)<<endl;

/*

&运算符的功能:

1、按位与

2、取地址

3、

*运算符的功能:

1、乘法

2、指针变量定义符

3、取内容(解引用)(间接引用运算符)

*/

int iValue3 = 100 , * pValue = &iValue3;

cout<<"通过变量名访问该变量的首地址:"<<&iValue3<<endl;

cout<<"通过指向该变量的指针访问该变量的首地址:"<<pValue<<endl;

cout<<"通过变量名访问该变量的内容:"<<iValue3<<endl;

cout<<"通过指向该变量的指针访问该变量的内容:"<<(*pValue)<<endl;

iValue3 = 800;

cout<<"---通过变量名修改了数据之后---"<<endl;

cout<<"通过变量名访问该变量的内容:"<<iValue3<<endl;

cout<<"通过指向该变量的指针访问该变量的内容:"<<(*pValue)<<endl;

(*pValue) = 1800;

cout<<"---通过指向该变量的指针修改了数据之后---"<<endl;

cout<<"通过变量名访问该变量的内容:"<<iValue3<<endl;

cout<<"通过指向该变量的指针访问该变量的内容:"<<(*pValue)<<endl;

cout<<"====="<<pValue<<endl;

cout<<"====="<<(void*)pValue<<endl;

/*

有类型的指针:N种

什么类型的指针指向什么类型的数据

原因:

有类型的指针包含2个方面的信息:

1、首地址

2、从该地址开始向下多少个字节代表一个数据

无类型的指针: 有且仅有1种:void* ,无类型的指针仅仅包含1个信息:首地址

特点:

1、能够指向任何数据类型

2、不能对无类型的指针进行解引用

3、可以强制转化成任何类型的指针

   (向一个无类型指针写入第二个信息)

*/

system("pause");

}

14.用指针变量访问数组元素:指向数组的指针变量称为数组指针变量。数组名会被解释成数组首元素的指针,即首个数组元素的地址。

15.可以通过下标形式或者指针偏移形式来访问数组中的元素。

16.二维数组指针变量的定义:类型说明符 (*指针变量名)[维数1];如下:int*p[4]它表示p是一个指针变量,它指向二维数组a或指向第一个一维数组a[0],其值等于aa[0]、或&a[0][0]

17.二级指针:如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。格式如下:类型说明符**指针变量名;

18.指向常量的指针:const  <数据类型>  *<指针变量>;该指针具有如下三个特点:

1)无法通过指针修改指向的数据;

2)可以修改指向;

3)该指针能够指向常量;

19.指针常量:const型指针<数据类型>  * const <指针变量>;特点如下:

修饰符const<指针变量>紧邻,说明<指针变量>不允许修改,但可以通过*<指针变量>修改指针所指向变量的值。

20.上述两者的区别主要看*const的位置。

21.指向const型变量的const型指针变量:const <数据类型>  *const <指针变量>;

特点:指向const型变量的const型指针变量既不可以修改<指针变量>的值,也不可以通过*<指针变量>修改指针所指向变量的值。

22.指针数组:每个元素都是一个指针。如:int *p[]

23.数组指针:指向一个数组的指针。int (*p)[]

24.代码如下图:

#include <iostream>

using namespace std;

void main()

{

//------指针与一维数组--------

int iArray1[5] = {101,2,3,4,5};

int * pArray1 = iArray1;

void * pVoidArray1 = iArray1;

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

{

//cout<<iArray1[i]<<endl;

//cout<<pArray1[i]<<endl;

cout<<*(pArray1+i)<<endl;

}

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

{

cout<<*pArray1<<endl;

++pArray1;

}

for (; pArray1 <= &iArray1[4]; ++pArray1)

{

cout << *pArray1 << endl;

}

//------指针与二维数组--------

cout<<"------指针与二维数组--------"<<endl;

int iArray2[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };

cout<<"二维数组的首地址:"<<iArray2<<endl;

cout<<"第一个一维数组的:"<<iArray2[0]<<endl;

cout<<"第二个一维数组的:"<<iArray2[1]<<endl;

cout<<"第三个一维数组的:"<<iArray2[2]<<endl;

int iArray3[][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };

int (*pArray3)[4] = iArray3;//指向二维数组的指针,

//该二维数组的每个一维数组由4个元素构成

 

for(int i = 0 ; i < 3 ; ++i)//行循环

{

for(int j = 0 ; j < 4 ; ++j)//列循环

{

//cout<<iArray3[i][j]<<endl;

//cout<<pArray3[i][j]<<endl;

cout<<*((*(pArray3+i))+j)<<"  ";//pArray3+i实现指向下一行   +j实现指向当前行的下一列  *(pArray3+i) 当前行首地址即当前一维数组的首地址

}

cout<<endl;

}

//指针数组:每个元素都是一个指针

cout<<"-----指针数组-----"<<endl;

int * pointerArray[4] = {NULL,NULL,NULL,NULL};

int a = 1 , b = 2 , c = 3 , d = 4;

pointerArray[0] = &a;

pointerArray[1] = &b;

pointerArray[2] = &c;

pointerArray[3] = iArray1;

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

{

cout<<*(pointerArray[i])<<endl;

}

//------二级指针------

int iValue4 = 10;

int * pValue4 = &iValue4;

int ** ppValue4 = &pValue4;

//直接使用变量

cout<<"iValue4的内容为:"<<iValue4<<endl;

cout<<"iValue4的地址为:"<<&iValue4<<endl;

//使用一级指针

cout<<"pValue4的内容 = iValue4的地址 = "<<pValue4<<endl;

cout<<"pValue4的地址为:"<<&pValue4<<endl;

//使用二级指针

cout<<"ppValue4的内容 = pValue4的地址 = "<<ppValue4<<endl;

cout<<"ppValue4的地址为:"<<&ppValue4<<endl;

cout<<"通过变量名访问变量:"<<iValue4<<endl;

cout<<"通过指向该变量的一级指针访问变量:"<<*pValue4<<endl;

cout<<"通过指向该一级指针的二级指针访问变量:"<<**ppValue4<<endl;

//---------二级指针应用---------

//定义了一个字符指针数组

char * ps[] = {"C","C++","Basic","C#","Java",

   "Delphi","Swift"};

char ** ppS = NULL;

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

{

ppS = ps+i;

cout<<*ppS<<endl;

}

cout<<ps[5][3]<<endl;

ppS = ps;

cout<<*(*(ppS+5)+3)<<endl;//二级指针 间接运算一下 得到一级指针

//int iArray[3];//普通数组的数组名 = 一级指针

//int * p = iArray

//int * pyyyy[3];//指针数组的数组名 = 二级指针

//int ** pp = pyyyy;

void * pVoidArray[10] = {};

system("pause");

}

25.指针与内存

26.程序内存空间分为四大块:代码区,全局变量和静态变量区,堆区,栈区。

1)代码区,存放系统的代码,即程序中的各个函数代码块。

2)全局数据区,存放程序的全局数据和静态数据。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。

3)堆区,存放程序的动态数据。程序在运行的时候用new申请任意多的内存,程序员自己负责在何时用delete释放内存。

4)栈区,存放程序的局部数据,即各个函数中的数据。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

27.new运算符:new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。

28.newdelete注意要成对出现,否则则会造成内存泄漏。

29.特别需要注意的是,如果该指针又指向了别处,那么在释放以前务必要保证指针从新指回原来的内存地址。最好开始时对这个地址进行备份。

30.delete释放的是内存空间,而不是指针。

31.在使用内存之前先检查内存是否为NULL

32.野指针:使用delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。不是NULL指针,是指向垃圾内存的指针。

33.代码如下图:

#include <iostream>

using namespace std;

 /*const的作用:1、修饰常量  2、用来修饰函数参数*/

int const c_iValue = 100;

 

 

//---------指针与常量----------

void main()

{

//--------指向常量的指针:const出现在*的前边--------

//定义格式: const 数据类型 * 指针名 = 初始值

//数据类型 const * 指针名 = 初始值

//特点:1、不能够通过解引用修改它所指向的数据,

//   简单理解该类型的指针为:“只读型”指针

//    2、指针的指向可以改变  

//3、这种类型的指针可以指向一个常量

int iValue1 = 10;

int const * pValue1 = &iValue1;

cout<<"通过常量指针访问数据:"<<*pValue1<<endl;

//*pValue1 = 100;//反例!!

iValue1 = 100;

cout<<"通过常量指针访问数据:"<<*pValue1<<endl;

int iValue2 = 20;

pValue1 = &iValue2; //指针的指向可以修改

cout<<"通过常量指针访问数据:"<<*pValue1<<endl;

const int c_iValue3 = 30;

pValue1 = &c_iValue3; //常量指针可以指向一个常量

cout<<"通过常量指针访问数据:"<<*pValue1<<endl;

//一个普通指针能够指向一个常量吗?  不可以

//int * pValue2 = &c_iValue3;//反例

system("pause");

}

//---------指针常量-----------

/*

定义格式:  数据类型 * const 指针名 = 初始值

特点:1、指针的指向一旦确定,就不允许修改该指针的指向

  2、对于通过指针常量访问、修改它所指向的内存中的

 数据都是可以的。

 3、这种指针不能指向一个常量

对于指针常量的理解:  门牌号

中关村大街18号 : 中关村互联网教育创新中心

 裁缝铺

 物流公司

 房地产公司

*/

//void main()

//{

//int iValue1 = 10;

//int * const pValue1 = &iValue1;

//cout<<"通过指针常量访问数据:"<< *pValue1 <<endl;

//*pValue1 = 20;//通过指针常量修改数据

//cout<<"通过指针常量访问数据:"<< *pValue1 <<endl;

//iValue1 = 30;

//cout<<"通过指针常量访问数据:"<< *pValue1 <<endl;

//int iValue2 = 40;

////不能修改指针常量的指向

////pValue1 = &iValue2;//反例!!!

////指针常量能够指向一个常量吗? 不可以

//const int c_iValue3 = 50;

//// int * const pValue2 = &c_iValue3;//反例!!!

//

//system("pause");

//}

//----------指向常量的常量指针-----------

/*

定义格式:

const 数据类型 * const 指针名 = 初始值

特点:

1、既能指向一个变量,又能指向一个常量

*/

//void main()

//{

//int iValue1 = 10;

//const int c_iValue2 = 20;

//const int c_iValue3 = 30;

//const int * const pValue1 = &iValue1;//指向了一个变量

//const int * const pValue2 = &c_iValue2;//指向了一个常量

//cout<<"通过指针访问数据:"<<*pValue1<<endl;

//iValue1 = 60;

//cout<<"通过指针访问数据:"<<*pValue1<<endl;

////*pValue1 = 40;//反例:不能通过指针修改数据

////pValue2 = &c_iValue3;//反例:不能修改指向

////c_iValue2 = 50;//反例:不能修改常量的值

//system("pause");

//}

----------“指向常量的指针”的应用-----------

加载资源

//void LoadResources( const char * _resource )

//{

//cout<<_resource<<endl;

//}

//void Test( const int * _pValue )

//{

////*_pValue = 30; //反例

//cout<<*_pValue<<endl;

//}

//void main()

//{

//LoadResources("C:\\Windows\\123.png");

//int iValue = 20;

//Test(&iValue);

//cout<<iValue<<endl;

//iValue = 30;

//Test(&iValue);

//cout<<iValue<<endl;

//const int c_iValue = 40;

//Test(&c_iValue);

//cout<<c_iValue<<endl;

//const char * ps = "HelloWorld";

//int iTemp = 1000;

//const int iValue8 = 20 , *pValue8 = &iTemp;

////*pValue8 = 99999;

//system("pause");

//}

#include <iostream>

using namespace std;

//--------手动申请内存、释放内存---------

//  new:申请 , delete :释放

void main()

{

// new 的使用方式:

// 数据类型 * 指针变量名 = new 数据类型(初始值);

// delete 的使用方式:

// delete 指针名; 指针名 = NULL;

//new int(10);//问题:内存泄漏

/*

指针使用步骤:

1、对指针的初始化(new)

2、使用该指针

3、释放(delete)指针所指向的存储空间 null

注意:在使用指针之前判定指针是否有效

*/

//----new的第一个用法:new一个单独的存储空间----

//在堆内存分配4个字节的存储空间,该存储空间的数据格式

//为:int,该存储空间的初始值为10

int * pValue1 = new int(10);

if (pValue1)

cout << *pValue1 << endl;

else

cout << pValue1 << endl;

if(pValue1)

{

delete pValue1;

pValue1 = NULL;

}

//----new的第二个用法:new一个连续的存储空间----

int iLength = 3;

//int * pArray1 = new int[iLength];

//memset(pArray1,-1,iLength*sizeof(int));

//for(int i = 0 ; i < iLength ; ++i)

//cout<<pArray1[i]<<endl;

//----练习:----

cout<<"请输入动态数组长度:";

cin>>iLength;

char * pCharArray = new char[iLength];

if(pCharArray)

{

memset(pCharArray,0,iLength*sizeof(char));

strcpy(pCharArray,"HelloNew[]");

cout<<pCharArray<<endl;

}

//对于连续new出来的内存空间的释放:

if(pCharArray)

{

delete [] pCharArray;

pCharArray = NULL;

}

//----练习:----

int iArray2[10] = {};

int * pArray2 = new int[5];

memset(pArray2,0,5*sizeof(int));

//pArray2 = iArray2;//反例:不能delete一个栈内存

delete [] pArray2;

pArray2 = NULL;

//------指针使用常见的内存错误---------

1、指针未初始化,就使用了

//int * pTemp;

//cout<<*pTemp<<endl;

2、使用了“空指针”

//int * pTemp = NULL;

//cout<<*pTemp<<endl;

//前两种问题的解决办法:都是在使用指针前判定指针是否为空

int * pTemp = NULL;

if(pTemp) //提高程序的“健壮性”strong

cout<<*pTemp<<endl; //提高程序的容错能力

else

cout<<"pTemp为NULL"<<endl;

3、内存虽然分配成功,但未正确赋初始值就使用了它

//int * pTemp1 = new int;

//cout<<*pTemp1<<endl;

//4、存储空间不足(访问越界)

//5、内存已经释放,但任然使用该内存

int * pTemp4 = new int(20);

if(pTemp4)

cout<<*pTemp4<<endl;

else

cout<<"xxxxxxxxx"<<endl;

delete pTemp4;//如果在delete后没有置NULL,该指针被称为“野指针”

pTemp4 = NULL;//防止“野指针”的办法:在delete后,置为NULL

if(pTemp4)

cout<<*pTemp4<<endl;

system("pause");

}

34.指针与引用

35.引用的基本概念:C++语言中的引用(reference)是其他变量的别名,因此,对引用变量的操作实际上就是对被引用变量的操作。<数据类型> &<引用变量名>=<变量名>;

36.当引用作为返回值时必须遵守:

1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了“无所指”的引用,程序会进入未知状态。

2)不能返回函数内部new分配的内存的引用。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成内存泄露。

37.常引用:const 类型标识符 &引用名= 目标变量名;用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

38.指针与引用的区别:引用与指针有很大的区别,指针是个变量,可以把它再次赋值成指向别处的地址,但是建立引用时必须初始化,并且决不会再关联其他的任何变量。

39.引用与指针在所占的内存上也有区别,引用的字节大小为当前所引用的数据字节大小,而指针在任何时候大小总是4.

40.引用在声明时,必须被初始化,而指针声明时可以不初始化,并且有空指针,无空引用。

#include <iostream>

using namespace std;

/*

---------引用----------

引用定义格式:

数据类型 &  引用名  =  被引用的量

引用:就是为变量取一个别名

引用的最大的作用:

来使得一个函数的某些参数变为向外进行数据传递

引用型参数的作用:

1、提高函数参数传递过程中的效率

2、函数内对形参的操作会直接影响实参的值

   (将参数变成向外进行数据传递)

*/

void getSum( int & _result , int _a , int _b )

{

_result = _a + _b;

}

void getSum( int * pResult , int _a , int _b )

{

*pResult = _a + _b;

}

//------引用类型作为函数的返回值类型-------

double & max(double &_d1 , double & _d2)

{

return _d1>_d2 ?_d1 : _d2;

}

//-------const型引用作为函数参数--------

void changeValue(const int &_iValue)

{

//_iValue+=10; //反例,常量引用参数,不能修改,只能访问

}

void main()

{

int iValue = 10;

int & refValue = iValue;

cout<<"0x"<<&iValue<<endl;

cout<<"0x"<<&refValue<<endl;//引用就是别名,别名就是替换

iValue = 20;

cout<<iValue<<endl;

cout<<refValue<<endl;

refValue = 30;

cout<<iValue<<endl;

cout<<refValue<<endl;

int iX = 3 , iY = 5;

int iResult = 0;

getSum(iResult,iX,iY);

cout<<iResult<<endl;

getSum(&iResult,iResult,iY);

cout<<iResult<<endl;

double dValue1 = 12.0 , dValue2 = 2.0;

max(dValue1,dValue2)+=24;

cout<<dValue1<<endl;

cout<<dValue2<<endl;

//-------“const型引用参数的函数”的调用--------

int iArray[10] = {1,2,3,4,5,6,7,8,9,10};

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

{

//changeValue(iArray[i]);  //反例,常量引用参数,不能修改,只能访问

}

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

{

cout<<iArray[i]<<endl;

}

//-----------指针与引用------------

cout<<"-----------指针与引用1------------"<<endl;

//指针与引用的区别:1、指针可以改变指向,但引用不可以改变

int iValue1 = 10;

int * pValue1 = &iValue1;

int & refValue1 = iValue1;

cout<<iValue1<<endl;

cout<<*pValue1<<endl;

cout<<refValue1<<endl;

int iValue2 =20;

pValue1 = &iValue2;

cout<<*pValue1<<endl;

//反例:不能先声明一个引用,再去为引用赋值

//int & refValue2 ;

//refValue2 = iValue2;

//注意:该行做的是取出iValue2的值,

//通过iValue1的引用refValue1赋值给iValue1,

//并没有让refValue1去引用iValue2.

refValue1 = iValue2;

cout<<refValue1<<endl;

cout<<"----"<<iValue1<<endl;

cout<<"-----------指针与引用2------------"<<endl;

//指针与引用的区别:2、在32位机器上指针永远占用4字节,引用取决于所引用的数据的大小--“别名”

short sValue1 = 30;

short & refShort1 = sValue1;

short * pShort1 = &sValue1;

cout<<"REF:"<<sizeof(refShort1)<<endl;

cout<<"POINTER:"<<sizeof(pShort1)<<endl;

cout<<"-----------指针与引用3------------"<<endl;

//指针与引用的区别:3、引用必须初始化,指针不需要,存在空指针,不存在空引用

int * pValue3;

int * pValue4 = NULL;

//int & refValue5; //反例:引用必须初始化

//-------指针的引用-------

cout<<"-------指针的引用-------"<<endl;

int * pTemp  = new int(5);

int* & pp = pTemp;

int & refpp = *pTemp;//为匿名“堆”空间取变量名,用引用指向匿名的int(5)

cout<<pTemp<<endl;

cout<<pp<<endl;

cout<<&refpp<<endl;

cout<<refpp<<endl;

*pTemp = 15;

cout<<refpp<<endl;

*pp = 25;

cout<<refpp<<endl;

refpp = 35;

cout<<refpp<<endl;

int iiii = 100;

pTemp = &iiii;

cout<<&iiii<<endl;

cout<<pTemp<<endl;

cout<<pp<<endl;

cout<<iiii<<endl;

cout<<*pTemp<<endl;

cout<<*pp<<endl;

pp = &refpp;

cout<<&refpp<<endl;

cout<<pTemp<<endl;

cout<<pp<<endl;

cout<<refpp<<endl;

cout<<*pTemp<<endl;//修改pp别名的指向, ptemp指针的指向也发生了改变

cout<<*pp<<endl;

delete pp;

pp = NULL;

system("pause");

}

41.当引用作为函数参数时,可以省去函数在调用时产生的副本对象的内存空间。

42.指针与函数的定义:定义一个指向函数的指针变量 p, 它不是固定指向哪一个函数的,而只是表示定义这样一个类型的变量,它是专门用来存放函数的内存地址的。函数指针指向的函数 应该和指针声明的函数类型(包括返回值,参数)完全一致

43.指向函数的指针在调用所指向的函数时,无需解引用,直接使用指针名代替函数名。(调用的时候和函数调用使用一样)

44.函数指针的数组:可以用来保存符合返回值和参数的一系列函数的内存地址。

45.例如以下声明了函数指针数组,可以保存5个返回值为int,参数为int的函数的内存地址。

int (*pf[5])(int);

46.指针函数:函数的返回值类型是一个指针类型。

47.避免返回局部变量或临时变量的地址的原因是,局部变量或者临时变量的内存释放后,导致当前指针指向无效的内存地址,所以使用指针函数时要注意返回的指针是否有效。以下代码,函数返回了无效的内存地址。

48.代码如下图:

#include <iostream>

using namespace std;

///*

//函数参数的传递形式:

//1、按值传递,特点: 复制机制,复制了数值,函数体内不能改变原来的值--用return 给原来的变量赋值,可以改变原来的变量

//2、按地址传递,复制了地址,可以在函数体内,直接改变原来的变量值

//*/

//----------函数参数的传递形式:按值传递,案例1------------

void printValue( int _iValue )

{

_iValue--;

cout<<_iValue<<endl;

}

//----------函数参数的传递形式:按值传递,案例2------------

void createMemory( int * _pValue , int _size )

{

cout<<"调用函数后:createMemory中的_pValue的地址为:"<<&_pValue<<endl;

_pValue = new int[_size];//内存泄漏,每次调用

//createMemory函数都会泄漏 _size*sizeof(int)个字节

}

//------函数参数的传递形式:按地址传递,案例1------

void printValue( int * _pValue )

{

if(_pValue)

cout<<*_pValue<<endl;

 

*_pValue = 20;

}

//------函数参数的传递形式:按地址传递,案例2------

void Test( int & _iValue )

{

cout<<_iValue<<endl;

_iValue = 30;

}

//------函数参数的传递形式:按地址传递,案例3------

//传指针的地址,实参需要给一个指针的地址,不能给一个二级指针

void createMemory( int* * _ppValue , int _size)

{

(*_ppValue) = new int[_size];

memset((*_ppValue),0,_size*sizeof(int));

}

void main()

{

//-----按值传递,案例1的调用-----

int iValue = 10;

printValue(iValue);

cout << iValue;

//-----按值传递,案例2的调用-----

int * pValue = NULL;

cout<<"调用函数前:main中的pValue的地址为:"<<&pValue<<endl;

createMemory(pValue,10);

//-----按地址传递,案例1的调用-----

printValue(&iValue);

cout<<iValue<<endl;

//-----按地址传递,案例2的调用-----

Test(iValue);

cout<<iValue<<endl;

//-----按地址传递,案例3的调用-----

int * pValue3 = NULL;

createMemory(&pValue3,10);

cout<<pValue3<<endl;

system("pause");

}

------------函数指针----------

//#include <iostream>

//using namespace std;

//int getSum(int _a , int _b )

//{

//return _a + _b;

//}

//int substract(int a , int b)

//{

//return a-b;

//}

函数指针作为函数参数

//void Test( int (*p)(int,int) )

//{

//cout<<p(3,5)<<endl;

//}

//void main()

//{

///*

//函数指针的概念:指向一个函数的指针

//函数指针的定义格式:

//函数返回值类型*函数指针名)(函数参数表) = 初始值;

//作用:用于在某些情况下对一个函数通过函数指针进行回调

//*/

//int (*pGetSum)(int,int) = getSum;

//cout<<"通过函数名调用函数:"<<getSum(3,5)<<endl;

//cout<<"通过指向函数的指针调用函数:"<<pGetSum(3,5)<<endl;

//for (int i = 1 ; i < 10 ; ++i)

//{

//if( i%2 == 0 )

//{

//Test(getSum);

//}

//else

//{

//Test(substract);

//}

//}

//

//system("pause");

//}

--------指针函数---------

//#include <iostream>

//using namespace std;

//int * createMemory(int _size)

//{

//int * p = new int[_size];

//return p;

//}

//int * printValue(int _iValue)

//{

//cout<<_iValue<<endl;

//return &_iValue;//有问题!!!!!!!

////返回临时变量的地址,会产生“野指针”

//}

//void main()

//{

///*

//指针函数的概念:返回值类型为指针的函数

//*/

//

//int * pResult = createMemory(10);

//for(int i = 0 ; i < 10 ; ++i)

//{

//pResult[i] = 10*i;

//}

//for(int i = 0 ; i < 10 ; ++i)

//{

//cout<<pResult[i]<<endl;

//}

//delete [] pResult;

//pResult = NULL;

//system("pause");

//}

//---指向“指针函数”的“函数指针”---

//#include <iostream>

//using namespace std;

//int * getValue()

//{

////函数内部的静态变量相当于一个:具有局部作用域的全局变量

//static int iValue = 100;

//cout<<iValue<<endl;

//return &iValue;

//}

//void main()

//{

///*

//指向指针函数的函数指针:终究它是一个函数指针,只不过

//它指向的函数是指针函数

//*/

//int * (*pGetValue)() = getValue;

//int * pTemp = pGetValue();

//cout<<*pTemp<<endl;

//*pTemp = 200;

//cout<<*pTemp<<endl;

//system("pause");

//}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值