文章目录
- 1. 引用和指针的区别?
- 2. C++中的指针参数传递和引用参数传递
1. 引用和指针的区别?
- 指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。
#include<iostream>
using namespace std;class solution {
public:void print() {cout << "print" << endl;}
private:int a;int b;
};
int main() {int* p1 = new int;double* p2 = new double;solution* p3 = new solution;cout << "字节数:" << sizeof(p1) << " " << "指针值所在内存地址:" << &p1 <<endl;cout << "字节数:" << sizeof(p1) << " " << "指针值所在内存地址:" << &p2 << endl;cout << "字节数:" << sizeof(p1) << " " << "指针值所在内存地址:" << &p3 << endl;return 0;
}
字节数:4 指针值所在内存地址:008FF9EC
字节数:4 指针值所在内存地址:008FF9E0
字节数:4 指针值所在内存地址:008FF9D4
从代码可以看出,指针都占用4字节的空间
#include<iostream>
using namespace std;int main() {double a = 3.14;double& b = a;cout << "b占用的字节数:" << sizeof(b) << " " << "b的地址:" << &b << endl;cout << "a占用的字节数:" << sizeof(a) << " " << "a的地址:" << &a << endl;return 0;
}
b占用的字节数:8 b的地址:00E3FC1C
a占用的字节数:8 a的地址:00E3FC1C
从代码可以看出,a和b的大小相同,并且所在地址相同,所以a就是b,b就是a,引用b是a的别名。
- 引用在定义的时候必须进行初始化,并且不能够改变。指针在定义的时候不一定要初始化,并且指向的空间可变。(注:不能有引用的值不能为NULL)
#include<iostream>
using namespace std;int main() {int a = 1;int b = 5;int* p;//正确,指针可以不进行初始化p = &a;cout << "*p=" << *p << " " << "a=" << a << endl;p = &b;//正确,指针的指向可以发生改变cout << "*p=" << *p << " " << "a=" << a << endl;return 0;
}
*p=1 a=1
*p=5 a=1
上面代码说明,指针可以不进行初始化,并且指针指向的变量可以发生改变。
#include<iostream>
using namespace std;int main() {int a = 1;int b = 5;int& r;//错误,引用必须进行初始化return 0;
}
运行错误
引用必须进行初始化
#include<iostream>
using namespace std;int main() {int a = 1;int b = 5;int& ref = a;ref = 3;cout << "a=" << a << " " << "ref=" << ref << endl;ref = b;cout << "a=" << a << " " << "ref=" << ref << endl;ref = 108;cout << "a=" << a << " " << "ref=" << ref << endl;return 0;
}
a=3 ref=3
a=5 ref=5
a=108 ref=108
以上代码说明,ref成为a的引用后,也即别名后,ref就和a绑定在一起,ref发生什么变化,a就发生什么变化,即ref和a的绑定关系不发生改变。
- 有多级指针,但是没有多级引用,只能有一级引用。
#include<iostream>
using namespace std;int main() {int** p;//正确,二级指针int&& r;//错误,没有多级引用return 0;
}
- 指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1)
#include<iostream>
using namespace std;int main() {double a = 3.14;double* p = &a;cout << "p指向的地址:" << p << endl;p++;cout << "p自增指向的地址:" << p << endl;int b=8;int& r = b;cout << "r=" << r << endl;r++;cout << "r=" << r << endl;return 0;
}
p指向的地址:00EFFC58
p自增指向的地址:00EFFC60
r=8
r=9
以上代码可以看出:p++会使得p指向地址变为下一个地址空间,因为p指向的变量类型为double型,所以地址值加8个字节;引用自增,会加1。
-
sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。
-
引用访问一个变量是直接访问,而指针访问一个变量是间接访问。
-
使用指针前最好做类型检查,防止野指针的出现;
-
引用底层是通过指针实现的;
-
作为参数时也不同,传指针的实质是传值,传递的值是指针的地址;传引用的实质是传地址,传递的是变量的地址。
2. C++中的指针参数传递和引用参数传递
-
指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(形参指针变了,实参指针不会变)。
-
引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。
#include<iostream>
using namespace std;void p_fun(int* p) {int a = 108;p = &a;
}void r_fun(int& r) {r = 100;
}
int main() {int value1 = 10;int* p = &value1;cout << "p指向的地址:" << p << endl;p_fun(p);cout<< "p指向的地址:" << p << endl;int value2 = 11;int& r = value2;cout << "value2=" << value2 << endl;r_fun(r);cout << "value2=" << value2 << endl;return 0;
}
p指向的地址:0075FB7C
p指向的地址:0075FB7C
value2=11
value2=100
指针作为参数传入函数,函数内部改变指针指向的地址值,并不影响主调函数内指针值;引用作为参数传入函数,函数内部改变引用的值,那么主调函数中的引用和引用绑定的变量都会发生改变。
-
引用传递和指针传递是不同的,虽然他们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将应用不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量(地址),那就得使用指向指针的指针或者指针引用。
-
从编译的角度来讲,程序在编译时分别将指针和引用添加到符号表上,符号表中记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。