返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >c++基础学习之如何区分引用和指针
  • 839
分享到

c++基础学习之如何区分引用和指针

2024-04-02 19:04:59 839人浏览 独家记忆
摘要

目录前言1.引用1.1引用的概念1.2引用的定义1.3引用与const1.4引用的使用场景2.指针2.1概念2.2获取对象的地址2.3利用指针访问对象2.3空指针2.4野指针2.4.

前言

对于我刚学c++的时候,最令我头疼的是引用和指针,老是区分不了它们,那么今天笔者将我的学习到的笔记总结出来,让大家少走一些坑。

术语:什么是对象?(对象在下面将会一直提到)

    c++程序员们在很多场合都会使用对象这个名词,通常情况下,对象是指一块能存储数据并具有某种类型的内存空间。有些人仅在与类有关的场景下才使用“对象”这个词。在这里,即认为对象是具有某种数据类型的内存的空间

1.引用

1.1引用的概念

引用为对象起另外一个名字,通过声明符写成&d的形式来定义引用类型,其中d是声明的变量名。


    int i = 10;
	int& refi = i;//refi是i的另外一个名字
	int& refi2;//报错:引用必须初始化

一个对象可以有多个引用,相当于给对象起多个名字。


    //refi,refi1,refi2与i绑定在一起
    int& refi1 = i;
	int& refi2 = refi1;

定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦引用无法重新绑定到另外一个对象,因此引用必须初始化。

定义引用后,对它进行所有的操作都是与之绑定的对象上进行的。


  refi = 100;//将100的值赋值给refi,即把值给i
  int j=refi;//与int j=i;是一样的

1.2引用的定义

允许在一条语句中定义多个引用,其中每个引用标识符都必须以符号&开头。


	int i = 10, int i1 = 10;//i和i1都是int型
	int& r = i, int i1 = i;//r是引用,与i进行绑定,i1是int
	int i3 = i1, & r2 = i1;//i3是int,r2是引用,与i1绑定一起
	int& r3 = i, & r4 = i;//r3和r4都是引用

除特殊情况下(下面会讲),引用需要与要绑定的对象严格匹配,而且引用只能绑定在对象上,不能与字面某个值或某个表达式的计算结果绑定在一起。


    int& refi = 10;//错误:引用类型的初始值必须是一个对象
	int i = 10;
	double& d = i;//错误:引用的类型必须是int型

1.3引用与const

把引用绑定到const对象上,我们称之为对常量的引用,与普通引用不同的是,对常量引用不能被做修改它所绑定的值。


    const int i = 10;
	const int& r1 = i;//正确:引用及其对应的对象都是常量
	const int& r2 = 200;//正确:引用及其对应的对象都是常量
	r1 = 40;//错误:r1是常量的引用,不能修改
	int& r2 = r1;//错误:r1是常量引用,只能读,r2是非常量引用,能读能修改

术语:c++程序员们经常把词组“对const的引用”简称“常量引用”。

在我们之前提到,引用的类型必须与其所引用的对象的类型一致,但是有两个例外,第一种是情况是初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换为引用类型即可,第二种是,常量引用可以绑定非const对象可以绑定。


	int i = 42;
	const int& r1 = i;//正确:允许将const int&绑定到一个普通int对象上
	const int& r2 = i * 2;//正确:r2是一个常量引用
	int& r3 = i * 2;//错误:r3是一个普通的非常量引用

而且对于常量引用还有更神奇的地方是:


	double d1 = 1.111;
	const int& r3 = d1;

上面的代码是正确的,r3是一个常量int类型的&引用,按理说应该只能绑定int类型的常量引用,单d1是一个double类型的对象 ,但编译器为了确保让r3绑定一个int类型对象,编译器自动把上述代码转换为:


	const int tmp = d1;//由double生成一个int类型的临时量
	const int& r3 = tmp;//让r3绑定这个临时量tmp

此处r3是绑定了临时量,而非d1对象,所谓的临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。

对const引用可以引用非const对象:


	int i = 10;
	int& r1 = i;
	const int& r2 = i;//正确:const引用可以引用非const对象,但是不能通过r2修改i
	r1 = 20;//正确:r1为非const引用,可以修改
	r2 = 30;//错误:r2为cosnt引用,不能对i进行修改

1.4引用的使用场景

1.做参数


 void Swap(int& left, int& right)
 {
    int temp = left;
    left = right;
     right = temp;
 }
  
int main()
{
   int a=0,b=10;
   swap(a,b);
}

引用可以用来做参数,把对象传给函数时,则函数中的参数则绑定到对应的对象中,不会产生临时变量例如:left则则是a的引用,right则是b的引用。

 2.做返回值


int& Count()
{
 static int n = 0;//n存在静态区中
 n++;
 return n; //返回对象是n的引用
}
 
int& Add(int a, int b)
 {
 int c = a + b;
 
 return c;
}
 
int main()
{
 //这是错误的:因为c出了函数作用域后则会被销毁,则c这块空间就不存在
 //ret引用就无效。
  int& ret=ADD(1,2);
}

总结:

如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已 经还给系统了,则必须使用传值返回。

2.指针

2.1概念

指针是“指向”另外一种类型的复合类型。指针是用来存储变量的地址,本身就是一个对象,允许对指针进行赋值和拷贝,而且指针的生命周期内它可以先后指向不同的对象。而且指针无需在定义时就对它初始化,它跟其它内置类型一样,如果没有初始化,也将拥有一个不确定的值。

定义指针时类型的方法将声明符写成*d的形式,其中d是变量名,如果在一条语句中定义了几个指针变量,每个变量名之前必须有*。


    int* i1, * i2;//i1和i2都是int类型的指针
	int d, * d1;//d是int对象,d1是指向int类型的指针

2.2获取对象的地址

指针是存放对象的地址,要想获取某个对象的地址,需要使用 &(取地址操作符)


	int i = 10;
	int* pi = &i;//pi存放变量的i的地址,或者说pi是指向变量i的指针

 注意:指针也是有大小的,它的大小根据在不同的平台是不同的,与指针的类型无关。

指针的大小在32位平台是4个字节,在64位平台是8个字节

在32位机器上,不管是int,char,double等内置类型,或者自定义类型,指针的大小永远都是4个字节。

除了特殊情况(下面会讲),指针的类型都要和它所指向的对象严格匹配。


 
	double d;
	double* pd = &d;//正确:pd是指向double对象的指针
	int* pi1 = &d;//错误:试图将double对象的地址给int类型的指针
    pi1=pd;//错误:指针pd和pi1的类型不匹配

2.3利用指针访问对象

如果指针指向了一个对象,那么想要通过指针访问对象,需要使用操作符 *(解引用操作符)


	int i = 10;
	int* pi = &i;//pi存放变量的i的地址,或者说pi是指向变量i的指针
 
	*pi = 20;//将i的值修改为20
	cout << *pi << endl;//输出的是i对象输出20

如上述,为*pi赋值实际上是为p所指的对象赋值。

注意:解引用仅适合那些确实指向某个对象的有效指针。

2.3空指针

空指针不指向任何对象,在使用一个指针之前,需要检查该指针是否为空指针。生成空指针的方法:


	int* p1 = nullptr;//等价于int *p1=0;
	int* p2 = 0;//直接将p2初始化为字面常量0
	//需要先#inclde cstdlib
	int* p3 = NULL;

把int变量直接赋给指针是错误的操作,即使int变量恰好等于0也不可以。


	int zero = 0;
	int* p4 = zero;//错误:不能将int变量赋值给指针

2.4野指针

2.4.1概念:

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

访问野指针,相当于去访问一个本不存在的位置上本不存在的对象。

2.4.2野指针的产生:


	int* p1;//指针没有初始化
	int arr[5] = { 0 };
	arr[5] = 11;//指针的越界访问
	int* ptr = (int*)malloc(sizeof(int));
	free(ptr);//指针指向的空间被释放

1.指针未初始化:

上诉中的p1是没有初始化的指针,它没有指向的空间,但它所占的内容将被看作一个地址值,糟糕的是,如果指针所占的空间恰好有内容,而这些内容恰好被当作一个地址,那么我们很难分清它到底是合法还是非法的。所以 建议初始化所有指针,如果不知道不清楚指针指向何处,就把它初始化为空指针。

2.指针的越界访问:

当指针指向的范围超出数组 arr 的范围时, p 就是野指针 ,当我们定义只能存储5个int类型的空间的数组,假设我们要去访问数组的第6个位置。由于第6个位置的空间没有定义出来,是未知的。所以arr[5]就是野指针。

3. 指针指向的空间释放:

当我们去malloc一块空间时,就会返回这个空间的指针去管理这块空间,当这块空间释放(销毁)掉时,但指针依然还在,指针指向的空间就未知的,就为野指针,所以我们释放一块空间时,我们需要把指针置为空,如ptr=nullptr。

2.5各个指针类型的含义

我们知道指针也有不同的类型,对于指针来说,指针的大小只和平台有关,相同平台下指针的大小都是一样的,那么指针的含义是什么?


	int n = 10;
	char* pc = (char*)&n;//pc为char类型的指针,但它指向n
	int* pi = &n;//pi为int类型的指针,指向n
 
	printf("%p\n", &n);//输出结果:012FF7E0
	printf("%p\n", pc);//输出结果:012FF7E0
	printf("%p\n", pc + 1);//输出结果:012FF7E1
	printf("%p\n", pi);//输出结果:012FF7E0
	printf("%p\n", pi + 1);//输出结果:012FF7E4

注意:%p是打印地址的符号,一个字节给一个对应的地址。

我们可以看出char类型的指针加1是走一个字节的距离,int类型的指针加1是走4个字节的距离。

同样的double类型的指针加1是走8个字节的距离。

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。


 //11223344是16进制数字,0x是16进制的标识符,每两个数字是一个字节
 int n = 0x11223344;
 char *pc = (char *)&n;//pc为char类型的指针,指向n
 int *pi = &n;//pi为int类型指针,指向n
 *pc = 0;   //i变为0x11223300
 *pi = 0;   //i变为0x00000000

pi和pc存放的都是n的地址,pc是char类型的指针,通过pc访问n的时候只能访问1个字节,所以*pc只改变一个字节的数值,pi是int类型的指针,通过pi访问n的时候只能访问4个字节,所以*pc改变4个字节的数值.

总结:指针的类型决定了指针能够访问对象有多少个字节的空间。

2.6 void* 指针

void*指针是一种特殊类型的指针,它可存放任意类型的指针.但我们无法确定对该地址中到底是个什么类型的对象。所以我们不能直接操作void*指针所指的对象。


	double d;
	void* pv = &d;//正确,d可以是任意类型的对象

利用void*指针能做的事比较有限,拿它和别的指针比较、作为函数的输入或输出或者赋给另外一个void*指针。

2.7指向指针的指针

指针是内存中的对象,同样指针也有地址,因此,允许把指针的地址在存放到另一个指针中。

  通过*的个数可以区别指针的级别,例如 **表示指向指针的指针,***表示指向指针的指针指针。


	int i = 0;
	int* pi = &i;
	int** ppi = &pi;//ppi指向pi的指针
	*ppi;//*ppi等于pi
	**ppi = 10;//**pi等于i

2.8指针与const

指向常量的指针不能用于改变它所指向的值,要想存放常量对象的地址,只能使用指向常量的指针


	const int i = 10;
	int* pi = &i;//错误:pi是一个普通的指针
	const int* pi1 = &i;//正确:pi1是一个指向常量的指针
	*pi1 = 20;//错误:pi1指向的值不能修改

允许另一个指向常量的指针指向一个非常量对象:


	int i1 = 10;
	pi1 = &i1;//正确:但不能通过pi1修改i1的值

指针是对象,所以允许指针本身定为常量,不能被修改,而且常量指针必须初始化,把const放在*之后,则说明指针是一个常量指针,常量指针不变的是指针本身,不是指针指向的值不能改变。


	int i2 = 0;
    int i3-10;
	int* const pi2 = &i2;//pi2一直指向i2
    pi2=&i3;//错误:pi2是一个常量指针   
    *pi2=12;//正确:pi2指向的值可以被修改
	const double d = 1.111;
	const double* const pd = &d;//pd是一个指向常量的常量指针
    *pd=2.22;//错误:pd指向的值不能被修改

 const在*之前是修饰指针指向的值,即指针指向的值不能被修改,const在*之后是修饰指针本身,即指针不能被修改。

3.指针和引用的区别

1.指针就是一个对象,允许对指针赋值和拷贝,引用是给对象多起一个名字,不创建对象。

2.指针定义时可以不初始化,引用定义时必须初始化。

3.引用初始化完成后,引用将和它绑定的初始值一直绑定在一起。指针可以先后指向几个不同的对象。

4.有多级指针,但没有多级引用。

5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

总结

到此这篇关于c++基础学习之如何区分引用和指针的文章就介绍到这了,更多相关c++区分引用和指针内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: c++基础学习之如何区分引用和指针

本文链接: https://lsjlt.com/news/133119.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • c++基础学习之如何区分引用和指针
    目录前言1.引用1.1引用的概念1.2引用的定义1.3引用与const1.4引用的使用场景2.指针2.1概念2.2获取对象的地址2.3利用指针访问对象2.3空指针2.4野指针2.4....
    99+
    2024-04-02
  • Go语言基础学习之指针详解
    目录1. 什么是指针2. 指针地址 & 指针类型3. 指针取值4. 空指针5. make6. new7. make 和 new 的区别8. 问题今天来说说 Go 语言基础中的...
    99+
    2022-12-30
    Go语言指针使用 Go语言指针 Go 指针
  • Linux 学习基础入门之Linux分区
    安装Linux,首先要有镜像文件,以CentOS为例,可以在官网或者国内某些镜像Server来获取镜像。根据自己的需要可以选择是 Everything 或者minimal iso.这里不写关于安装的细节,对于其中的一些关键步骤做些说明。1....
    99+
    2023-06-05
  • 如何掌握C++指针基础
    这篇文章给大家介绍如何掌握C++指针基础,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++指针就像是其它变量一样,所不同的是一般的变量包含的是实际的真实的数据,而指针是一个指示器,这些都是一些C++指针基础性的问题,...
    99+
    2023-06-17
  • C++学习之指针的使用详解
    C++中指针储存一个地址 声明: datatype* p;  datatype表示指针指向的数据类型。 int num=0; int* pnum=&num; //&...
    99+
    2023-03-02
    C++指针使用 C++指针
  • 从头学习C语言之指针和数组
    目录指针和数组:示例:总结指针和数组: 数组名其实是数组第一个元素的地址。 %p用来打印地址,为十六进制 &:取址操作符 如果用一个指针指向数组,应该怎么做呢? char ...
    99+
    2024-04-02
  • C语言学习之指针的使用详解
    目录一、指针概念1.指针变量2.指针类型3.二级指针二、野指针1.野指针成因2.规避野指针三、指针运算1.指针±整数2.指针-指针3.指针关系运算四、指针数组1.指针和...
    99+
    2022-11-13
    C语言指针使用 C语言指针
  • 如何使用 C++ 引用和指针传参?
    c++++ 中引用和指针都是传递函数参数的方法,但有区别。引用是变量的别名,修改引用会修改原始变量,而指针存储变量的地址,修改指针值不会修改原始变量。在选择使用引用还是指针时,需要考虑是...
    99+
    2024-04-13
    指针 引用 c++
  • C++的引用和指针有哪些区别
    本篇内容主要讲解“C++的引用和指针有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++的引用和指针有哪些区别”吧!引用和指针有如下三种区别:1 引用必须在声明时初始化,而指针不用;2...
    99+
    2023-06-17
  • 深入学习C++智能指针之shared_ptr与右值引用的方法
    目录1. 介绍2. 初始化方法2.1 通过构造函数初始化2.2 通过拷贝和移动构造函数初始化2.3 通过 std::make_shared 初始化2.4 通过 reset 方法初始化...
    99+
    2024-04-02
  • C++引用和指针的区别你知道吗
    目录引用1.引用概念2.格式3.引用特性4.常引用1.const引用5.使用场景1、引用作为参数2. 引用作为做返回值6.引用和指针的区别7.引用和指针的不同点:总结引用 1.引用概...
    99+
    2024-04-02
  • C++学习进阶篇之类大小计算和this指针
    目录一、类大小计算二、this指针总结一、类大小计算 类的大小是只计算它的成员变量或者自定义成员,不会计算它的成员函数大小。 #include<iostream> usi...
    99+
    2023-05-18
    c++类大小计算方式 c++计算类的大小 c++ this指针用法
  • C++学习进阶之Makefile基础用法详解
    目录1. Makefile基本语法与执行2. Makefile简化过程3. Makefile生成并使用库3.1 动态库的建立与使用3.2 动态加载库的建立与使用总结1. Makefi...
    99+
    2024-04-02
  • C++中指针,引用和STL的示例分析
    这篇文章主要介绍C++中指针,引用和STL的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!对象的定义:对象是指一块能存储数据并具有某种类型的内存空间一个对象a,它有值和地址;运行程序时,计算机会为该对象分配存...
    99+
    2023-06-29
  • python培训之零基础如何学习pyth
    老男孩python培训教你如何零基础学python根据TIOBE最新排名,Python已超越C#,与Java,C,C++成为全球前5大流行编程语言之一。从云端、客户端,到物联网终端,python应用无处不在。从国内的百度、阿里、腾讯、网易、...
    99+
    2023-01-31
    基础 python pyth
  • C++学习之移动语义与智能指针的实例分析
    这篇文章给大家分享的是有关C++学习之移动语义与智能指针的实例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。移动语义1.几个基本概念的理解(1)可以取地址的是左值,不能取地址的就是右值,右值可能存在寄存器,也...
    99+
    2023-06-15
  • 如何分析C++数组和指针的区别与联系
    这期内容当中小编将会给大家带来有关如何分析C++数组和指针的区别与联系,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。前言:一直以来,有很多地方在说到数组和指针时都会说数据就是指针,这种观点也被越来越多的人...
    99+
    2023-06-26
  • C++ 函数中引用参数和指针参数的区别
    在 c++++ 函数中,引用参数传递变量地址,对参数的修改影响原始变量,而指针参数传递指向地址的指针,对参数的修改不影响原始变量。 C++ 函数中引用参数和指针参数的区别 在 C++ ...
    99+
    2024-04-20
    引用参数 指针参数 c++ 内存占用
  • C++智能指针之shared_ptr如何使用
    这篇文章主要介绍“C++智能指针之shared_ptr如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++智能指针之shared_ptr如何使用”文章能帮助大家解决问题。std::share...
    99+
    2023-06-30
  • C#基础入门之值类型和引用类型的区别详析
    目录一、值类型和引用类型的区别 1、赋值时的区别 2、内存分配的区别 3、来自继承结构的区别 二、总结 一、值类型和引用类型的区别 .NET的类型可以分为两类:值类型和引用类型。这...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作