今天看了两个小时<<21天学通C++>>把C++中的指针、引用、传值问题弄清楚了
今天看了两个小时<<21天学通C++>>把C++中的指针、引用、传值问题弄清楚了
?
记住引用理解成别名
?
?
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。 形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。
?
声明指针
//声明一个空指针 p
int *p = 0;
?
int pTmp; = 50;
int *p = & pTmp; <==> int *p ;
??????????????????????????????????? *p = & pTmp;
?????? 其中 p里面存放的是 pTmp的地址,
????????????? & 取地址符号
*p = & pTmp 只有在指针初始化时这样用,其实这种写法容易引起歧义;
????????????? 此时:
????????????? p 中存放的是pTmp的地址;
????????????? *p 指的是指存储在指针的内存地址中的值 也就是pTmp的值;
????????????? &p 取指针本身的地址
????????????? 所以:
????????????? cout<<*p // output : 50;
cout<<p // output : 0x22ff56是pTmp变量所在的地址值;
cout<<&pTmp // output : 0x22ff56 是pTmp变量所在的地址值;
cout<<&p // output : 0x32fe88 是p本身的地址值;
p指向变量,对p重新赋值就会改变p所指向变量的值,同样对p指向的变量重新赋值也会改变*p的值。
注意:
如果是char数组或者int数组时
定义方法:
?????char *p1 = "name"; <==> char s[ ] = "name"; char *p1; p1 = s;
printf("%s\n",p1);//这里是 p1 output: name
printf("%c\n",*p1);//output: n
?
???? int b[3] = {15,19,20};
int *i;?????????????????????????? <==> int *i = {15,19,20};
i = b;
printf("%d \n",*i);//这里是 *i output:15
?
ps:指针赋值问题
????? char * p1 ="name";
????? char *p2;
????? p2 = p1;//正确
????? while(*p2++ = *p1++) ;//错误
???? 因为p1++每执行一次,指针就会后移一位,到末尾时指向"\0",故执行完后p2 为NULL
指针控制循环问题
?
当为int型数组时 ,不能用指针来作为循环条件
int arr[20];
int *ptr = arr;
int i;
for(i=0;i<20;i++)
{
???? ptr++; //指针加1
??? (*ptr)++;//指针指向内容加1
}
?
当为char型数组时
char *p="abc";
while(*p)?? // 当*p为‘/0’时终止
{
???? printf("%d\n",*p);
??? p++;
}
?
?
引用实际是其他变量的别名,对应用的操作就是对其引用的变量的操作
int pTmp1 = 20;
int pTmp2 = 22;
?????? int &p = pTmp1; //初始化的方式
?
?????? 引用重新赋值问题,会改变其引用的变量的值
?????? p = pTmp2;
?????? 则:
?????? cout<< p // output : 22;
?????? cout<< pTmp1 // output : 22;
???
3传参
代码1:
#include <iostream>
using namespace std;
void swap(int x,int y);
int main()
{
???? int x = 5,y = 10;
???? cout<<"main:before swap x = "<<x<<" y = "<<y<<"\n";//output: x=5,y=10
???? swap(x,y);
???? cout<<"main:after swap x = "<<x<<" y = "<<y<<"\n";//output: x=5,y=10
???? //return 0;
}
?
void swap(int x,int y)
{
????? int tmp;
????? cout<<"swap:before swap x = "<<x<<" y = "<<y<<"\n"; //output: x=5,y=10
????? tmp = x;
????? x = y;
????? y = tmp;
????? cout<<"swap:after swap x = "<<x<<" y = "<<y<<"\n";//output: x=10,y=5
}
注意:#define swap(a,b) a=a+b;b=a-b;a=a-b; 这种形式就会影响实参
?
代码2
#include <iostream>
using namespace std;
void swap(int *x,int *y);
int main()
{
???? int x = 5,y = 10;
???? cout<<"main:before swap x = "<<x<<" y = "<<y<<"\n";//output: x=5,y=10
???? swap(&x,&y); // xy的地址被做为参数传递给swap
???? cout<<"main:after swap x = "<<x<<" y = "<<y<<"\n";//output: x=10,y=5
???? //return 0;
}
?
void swap(int *x,int *y) // int *x = &x ,int *y = &y
{
????? int tmp;
????? cout<<"swap:before swap x = "<<*x<<" y = "<<*y<<"\n"; //output: x=5,y=10
????? tmp = *x;
????? *x = *y;
?? ???*y = tmp;
????? cout<<"swap:after swap x = "<<*x<<" y = "<<*y<<"\n";//output: x=10,y=5
}
?
?
代码2
#include <iostream>
using namespace std;
void swap(int &x,int &y);
int main()
{
???? int x = 5,y = 10;
???? cout<<"main:before swap x = "<<x<<" y = "<<y<<"\n";//output: x=5,y=10
???? swap(x,y); // 变量x y 被做为参数传递给swap
???? cout<<"main:after swap x = "<<x<<" y = "<<y<<"\n";//output: x=10,y=5
???? //return 0;
}
?
void swap(int &rx,int &ry) // int &x = x ,int &y = y 这里rx 和 ry是 x
y 的别名
{
????? int tmp;
????? cout<<"swap:before swap x = "<<*rx<<" y = "<<*ry<<"\n"; //output: x=5,y=10
????? tmp = rx;
????? rx = ry;
????? ry = tmp;
????? cout<<"swap:after swap x = "<<rx<<" y = "<<ry<<"\n";//output: x=10,y=5
}
?
C++指针与引用int & *p; //不能建立指向引用的指针;int *a; int * & p=a; //正确,指针变量的引用
?引用和指针使用原则:
1.在可以用引用的情况下,不要用指针;
2.引用不允许重新赋值.,当使用一个变量指向不同的对象时,必须用指针;
3.引用不允许为空,当存在对象为空时,必须使用指针。
引用说明:
(1) double & rr=1; 等价与 double temp; temp=double(1); double & rr=temp;
(2) int *a; int * & p=a; int b=8; p=&b; //正确,指针变量的引用
void & a=3; //不正确,没有变量或对象的类型是void
int & ri=NULL; //不正确,有空指针,无空引用
(3) int & ra=int; //不正确,不能用类型来初始化
int *p=new int; int & r=*p; //正确
(4) 引用不同于一般变量,下面类型声明是非法的:
int &b[3]; //不能建立引用数组
int & *p; //不能建立指向引用的指针
int &&r; //不能建立引用的引用
(5) 当使用&运算符取一个引用的地址时,其值为所引用变量的地址,
?
一段代码:
1?#include?<iostream>
?2?
?3?using?namespace?std;
?4?
?5?void?freePtr1(int*?p1)
?6?
?7?{
?8?
?9????delete?p1;
10?
11????p1?=?NULL;
12?
13?}
14?
15?void?freePtr2(int*&?p2)
16?
17?{
18?
19????delete?p2;
20?
21????p2?=?NULL;
22?
23?}
24?
25??
26?
27?void?main()
28?
29?{
30?
31????int?*p1?=?new?int;
32?
33????*p1?=?1;
34?
35????freePtr1(p1);
36?
37????int?*p2?=?new?int;
38?
39????*p2?=?2;
40?
41????freePtr2(p2);
42?
43????system("pause");
44?
45?}
思考:在freePtr1和freePtr2 的比较中,你能发现它们的不同点吗?
?
二、对代码进行解释:
#include <iostream>
using namespace std;
void freePtr1(int* p1)
{
?? //未释放内存前 ->? p1 Address : 0012FDDC? p1 value : 003429B8,在这里,p1它也是一个变量,既然是一个变量,那么它将会以值的传递,把外部变量p1传到栈内,在栈内产生一个地址:0012FDDC,当然,它的值不会变仍然是指向堆地址:003429B8 。
?? delete p1; //系统回收p1值的地址003429B8处的内存。
p1 = NULL;//对p1赋以NULL值即:00000000,注意:p1本身的地址并没有变,变的是p1的值。
?? //释放内存后 ->? p1 Address : 0012FDDC? p1 value : 00000000,出栈后,p1由于是一个临时对象,出栈后它会自动被视为无效。
}
void freePtr2(int*& p2)
{
?? //未释放内存前 ->? p2 Address : 0012FEC8? p2 value : 003429B8,p2是一个指针的引用,即引用指向指针,记住引用的特点:对引用的对象直接操作。所以它的地址和值与栈外的main()函数中,p2的值是同一个。
?? delete p2; //对p2所引用的指针进行释放内存,即:系统回收main()函数中 p2的值 003429B8 地址处的内存。
?? p2 = NULL;//对main()函数中p2的指针赋以NULL值。
?? //释放内存后 ->? p2 Address : 0012FEC8? p2 value : 00000000,由于操作的对象都是main()函数中的p2,所以它将应用到原变量中。
}
?
void main()
{
?? int *p1 = new int;
//释放内存前->? p1 Address : 0012FED4? p1 value : 003429B8
?? freePtr1(p1);
?? //释放内存后->? p1 Address : 0012FED4? p1 value : 003429B8
?
?? int *p2 = new int;
?? //释放内存前->? p2 Address : 0012FEC8? p2 value : 003429B8
?? freePtr2(p2);
?? //释放内存后->? p2 Address : 0012FEC8? p2 value : 00000000
?? system("pause");
}
-----------------------------------------------
指针引用的经典用法:
#include <iostream>
using namespace std;
void all1(int **p)
{
?int *pp = new int;
?*p = pp;
}
void all2(int*& p)
{
?int *pp = new int;
?p = pp;
}
void main()
{
?int *a1;
?all1(&a1);
?*a1 = 1;
?cout<<*a1<<endl;
?int *a2;
?all2(a2);
?*a2 = 2;
?cout<<*a2<<endl;
}