C语言学习四引用(引用和多级指针的对比)

引用

        定义:为对象起了另外一个名字,引用类型去引用另一种类型,通过将声明符写成&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关键字。例如函数仅仅用来打印主函数中的信息)


3、一旦初始化完成,引用将和它的初始值一直绑在一起,因为无法将引用绑定到另一个对象,因为引用没有地址,说明他恒定不变,那他就拥有常量的性质,常量声明时必须初始化,而且只能初始化一次
#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,指向数组的引用;

猜你喜欢

转载自blog.csdn.net/boy_of_god/article/details/81022316