定义:为对象起了另外一个名字,引用类型去引用另一种类型,通过将声明符写成&d的形式来定义引用类型,其中d是声明的引用类型的变量名。&d:表示引用变量中存储的内容(即引用所指向的变量的地址);d:表示以引用变量中存储的内容为地址的变量中的值。引用变量和指针变量一样都是存的所指向变量的地址,不同点指针自身变量自身有地址,而引用变量没有地址(系统为引用变量自身分配了地址,只不过引用变量自身的地址我们连读的权限都没有,所以我们默认引用自身没有地址,即引用类似常量),所不能声明引用的引用,也不能声明指向引用的指针,但是可以声明指向指针的指针,也可以声明指向指针的引用
分析两端段代码:
int i= 10;
int j = 20;
int &r = &i;
r = j;//引用变量的r实际是以引用变量r中存的内容为地址的变量中的值,实质r就是i
代码二
int a = 10;
int *p = &a;
*P =5;//*运算是以指针变量p中存的内容为地址的变量中的值
**引用系统为其分配内存空间,引用变量和指针变量一样都是存址(引用变量中存储的是他所指向的变量的地址)
#include<stdio.h>
int main()
{
char k = 'a';
int i = 10;
double j = 20.0;
char &r = k;
char* p = &k;
int &r1 = i;//引用
int *p1 = &i;
double &r2 = j;
double *p2 = &j;
printf("======存地址的变量系统会分配4个字节===\n");
printf("char类型的引用变量分配了%d个字节\nchar*类型的指针变量分配了%d个字节\n",sizeof(&r),sizeof(p));
printf("int类型的引用变量分配了%d个字节\nint*类型的指针变量分配了%d个字节\n",sizeof(&r1),sizeof(p1));
printf("double类型的引用变量分配%d个字节\ndouble*类型的指针变量分配%d个字节\n\n",sizeof(&r2),sizeof(p2));
printf("===引用变量和指针变量中存的都是他们所指向的变量的地址\n");
printf("&k = %Xf\t&r = %Xf\tp = %Xf\n",&k,&r,p);
printf("&i = %Xf\t&r1 = %Xf\tp1 = %Xf\n",&i,&r1,p1);
printf("&j = %Xf\t&r2 = %Xf\tp2 = %Xf\n\n",&j,&r2,p2);
printf("===引用变量名与指针变量*运算后的结果相同===\n");
printf("k = %c\t\tr = %c\t\t*p = %c\n",k,r,*p);
printf("i = %d\t\tr1 = %d\t\t*p1 = %d\n",i,r1,*p1);
printf("j = %lf\tr2 = %lf\t*p2 = %lf\n",j,r2,*p2);
return 0;
}
运行结果:
1、引用类型的的变量在声明的同时必须初始化,因为引用似常量所以必须声明时初始化,更没有引用的引用即没有int && i = &j,指针却有指针的指针,因为指针自身的地址我们有读的权限)
#include<stdio.h>
int main()
{
int i = 10;
/*
int &r ;//error C2530: 'r' : references must be initialized引用声明时必须初始化
r = i;
*/
int &r = i;//正确
return 0;
}
2、引用的赋值:一般初始化变量时,初始值会被拷贝到新建的对象中,然而定义引用时,程序把引用和它的
初始值 绑定在一起,而不是将初始值拷贝给引用,引用即被绑定变量的别名。引用并不是对象(即引用类型的
变量自身的地址我们无法进行读写操作,然后我们就说引用类型变量没有地址(它里面存的是绑定的变量的地址))
相反的,它只是为一个已经存在的对象所起的另外一个名字
#include<stdio.h>
int main()
{
int i = 10;
int j = 20;
int &r = i;
r = j;//此时引用(指向)了一个整形变量,此时给r赋值,就是给i赋新值。此时i中的值也是j(即20)
//换句话说把变量j的值赋值给以引用变量i中所存放的内容为地址的变量
printf("i = %d\n",i);
return 0;
}
运行结果:
2-1、通过函数传参可以实现通过被调函数为主调函数中的变量赋值。形参为引用类型(效率比用指针好)
#include<stdio.h>
void rfun(int &r);
int main()
{
int i = 10;
printf("i = %d\n",i);
printf("======调用函数后i的值为======\n");
rfun(i);//通过函数传参来修改主调函数中的变量
printf("i = %d\n",i);
return 0;
}
void rfun(int &r)
{
r = 20;//把20赋值给以引用变量r中存储的内容为地址的变量
}
运行结果:
***此处经常变换成函数传引用来代替和普通变量中的函数传值。(如果不希望被调函数改变主调函数
中的变量的值时可使用const关键字。例如函数仅仅用来打印主函数中的信息)
#include<stdio.h>
int main()
{
int i = 10;
int j = 20;
int &r = i;
//int &r = j;//报错error C2374: 'r' : redefinition; multiple initialization不能重复初始化
return 0;
}
4、因为引用本身不是一个对象,引用变量没有实际的地址,所以不能定义引用的引用&r(而指针是一个对象,
即指针变量有地址,可以定义指向指针的指针)例如:
#include<stdio.h>
int main()
{
int i = 10;
int &r = i;
// int &&r1 = &r;报错不能声明引用的引用,因为引用本身没有地址&r是引用变量中存储的内容(它是引用所指向的变量的地址)
return 0;
}
***通常什么样的类型的变量自身有地址,我们就可以定义什么样类型的引用变量来绑定那个变量,也可以定义什么样类型的指针来指向那个变量。
***什么样类型的变量可以声明为常量?:自身有地址我们把他自身的地址弄成恒定不变那么他就成常量了,或者或什么样类型的变量变量有地址,但是我们访问不到这时候我们说这种类型自身的地址就是恒定不变,例如引用,那么我们也可以把这种类型声明为常量。(下一篇讨论)
***5、我们可以定义指向指针的引用(定义一个引用变量来绑定一个指针变量)int *&引用变量名 = 值真变量名;(一级指针引用)int** &r =*p;(二级指针引用);
基础概念(重要的地方说三遍): int i = 10;
int *p = &i;//指针
int j = 20;
int &r = j;//引用
p:表示指针变量p中所存的值(此处为变量i的地址)
&p:表示指针变量p本身的地址(上一篇指针之多级指针中有介绍)
*p:表示以指针变量p中存储的内容为地址的变量的值(此处为变量i的值)
&r:表示引用变量r中所存放的值(此处为变量j的地址)
r:表示以引用变量r中存储的内容为地址的变量的值(此处为变量j的值)
5.1在指向指针的引用中的各个变量的地址和变量值的关系分析
#include<stdio.h>
int main()
{
int i = 10;
int* p = &i;
int* &r = p;//把指针变量p本身的地址(&p)赋值给引用变量r,此时引用变量r中
printf("引用变量中存的值为: &r = %Xf\n指针变量本身的地址为: &p = %Xf\n\n",&r,&p);
printf("======华丽的分割线======\n\n");
printf("变量i的地址为:\t &i = %Xf \n指针变量p中存的值为: p = %Xf\n引用变量所引用的变量的值: r = %Xf\n",&i,p,r);
return 0;
}
运行结果:
分析图:
5.1、通过操作指向指针的引用的变量,从而达到改变指针所指向的变量的值
#include<stdio.h>
int main()
{
int i = 10;
int* p = &i;
int* &r = p;
printf("i = %d\n",i);
*r = 30;//实际因引用变量中存放的内容为地址的变量中的值(即真变量p中存放的值)在进行*运算
printf("通过改变指向指针变量的引用的引用变量,来改变指针所指向的变量的值:i = %d\n",i);
return 0;
}
运行结果:
5.1.2、用函数实现通过操作指向指针的引用的变量,从而达到改变指针所指向的变量的值。实参是指针变量形参是指向指针的引用
#include<stdio.h>
void fun(int* &r)
{
*r = 30;//引用变量就是指针变量的一个别名,【最重点的语句】
}
int main()
{
int i = 10;
int*p = &i;
printf("i = %d\n",i);
fun(p);
printf("用函数实现通过改变指向指针的引用的变量,从而达到改变指针所指向的变量的值:i = %d\n",i);
return 0;
}
运行结果:
5.2、通过操作指向指针的引用的变量,从而达到改变指针变量中的值
#include<stdio.h>
#include<malloc.h>
int main()
{
int *p = NULL;
printf("指针变量的初始值为: p = %X\n",p);
int * &r = p;//【重点语句】
r = (int*)malloc(sizeof(int)*4);【重点语句】
printf("通过操作指向指针的引用变量来改变指针变量中的值: p = %X\n",p);
printf("======华丽的分割线======下面是释放内存这次不讨论===\n");
free(p);//释放动态内存
p = NULL;
if(p != NULL)
{
printf("%d\n",*p);
}
return 0;
}
运行结果:
5.2.1调用函数通过操作指向指针的引用的变量,从而达到改变指针变量中的(值实参为指针变量形参为指向指针的引用)
#include<stdio.h>
#include<malloc.h>
void fun(int* &r);//函数的声明此函数的功能是开辟动态内存的
void funDest(int* &r);//释放内存
int main()
{
int *p = NULL;
printf("指针变量的初始值为: p = %X\n",p);
fun(p);
printf("通过操作指向指针的引用变量来改变指针变量中的值: p = %X\n",p);
funDest(p);//释放内存
return 0;
}
void fun(int *& r)
{
r = (int*)malloc(sizeof(int)*4);//引用变量r是主调函数中指针变量p的一个别名【重点语句】
printf("我是在函数中分配的动态内存的首地址: r = %X\n",r);
}
void funDest(int* &r)
{
free(r);
r = NULL;
}
运行结果:
6.1、通过指向指针的指针即多级指针也能改变指针变量中存的值,只不过没有指向指针的引用好用,实参指针变量的地址,形参指向指针的指针
#include<stdio.h>
#include<malloc.h>
int main()
{
int* p = NULL;
int**q = &p;//二级指针用于指向一级指针【重点语句】
printf("指针变量p中存放的地址为: %X\n",p);
*q = (int*)malloc(sizeof(int)*4);//通过二级指针给一级指针变量赋值【重点语句】
**q = 12;【重点语句不懂可以看上一篇中指针中的多级指针】
printf("malloc函数申请的动态内存首地址为: %X\n",*q);
printf("指针变量p中存放的地址为: %X\n",p);
printf("======下面打印的结果是关于内存释放传哪个值=====传哪个都一样\n");
printf("**q = %d\t*p = %d\n",**q,*p);
//free(*q);
free(p);
printf("%d\t%d\n",**q,*p);
printf("=====打印的值为-572662307表示已经释放===\n");
return 0 ;
}
运行结果:
6.1.1调用函数通过操作多级指针从而来改变一级指针变量中的值
#include<stdio.h>
#include<malloc.h>
void fun(int**q);//声明开辟内存的函数
void funDest(int**q);//声明释放动态内存的函数
int main()
{
int *p =NULL;
printf("主调函数指针p原来的值: %X\n",p);
fun(&p);
printf("通过函数修改主调函数中指针变量的值后,主调函数中指针变量p的值为: p = %X\n",p);
fun(&p);//释放内存
return 0;
}
void fun(int**q) //通过此函数来改变主函数中的指针变量的值
{
*q = (int*)malloc(sizeof(int));//以q中存放的内容(指针变量p的地址&p)为地址的变量的值(即指针变量p中的值)【重点语句】
printf("通过函数申请的内存首地址为:*q = %X\n",*q);
}
void funDest(int**q)
{
free(*q);////释放的是以q中存的内容为地址(即指针变量p的地址)的变量的值(即指针变量p的值)
}
运行结果:
不能定义指向引用的引用
也不能定义指向引用的指针
6、&运算符和*运算符的讨论
&出现在声明中的&是引用声明符,其他情况当做取地址符
*出现在指针变量前面叫做:对指针变量进行*运算
*出现在一个指向指针的引用的引用变量的前面叫做:对引用变量进行解引用
7,指向数组的引用;