1.指针的概念:指针是存储内存地址的变量,指向一个数据结构的首地址。
2.指针的内存大小只有四个字节。
3.三种声明指针类型的方式:类型名 *变量名;类型名* 变量名;类型名 * 变量名;
4.一次定义多个指针变量,每个指针变量前必须加“*”,否则,只有前面加“*”的才能被解释成指针。
5.给指针变量赋值时需要注意:1)未经赋值的指针变量不能使用。2)指针变量的赋值只能赋予地址, 决不能赋予任何其它数据。
6.给指针赋值的六种方式:
7.NULL是一个指针常量,表示空地址。当指针变量暂时无法确定其指向或暂时不用时,可以将它指向空地址,以保证程序的正常运行。
8.指针的运算:指针加上或减去一个整数n,表示指针从当前位置向后或向前移动n*sizeof<数据类型>大小的地址空间。
9.两个指针相减:当两个指针指向同一数组时,两个指针的相减才有意义,两个指针相减的结果是一个整数,表示两个指针之间数组元素的个数。
10.两个指针的比较运算:
pf1==pf2 表示pf1和pf2指向同一数组元素;
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],其值等于a、a[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.new和delete注意要成对出现,否则则会造成内存泄漏。
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");
//}