首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
勤劳的哈士奇在改简历
西北工业大学 C++
关注
已关注
取消关注
@赛博二哈:
【指针】03.指针和引用、万能指针、野指针、智能指针
【嵌入式八股】一、语言篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM 【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym 【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM 【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0 其他 指针和引用 32.指针和引用的异同是什么? 相同 都可以用于访问内存中的变量或对象。 都可以作为函数参数,传递变量或对象的引用或地址。 都可以用于动态分配内存,并在程序中进行内存管理。 都可以用于实现数据结构,如链表、树等。 都可以作为成员变量出现在类中,并用于实现类的数据成员和成员函数。 区别(区别很多,记这几个够了) 内存模型不同: 指针是一个变量,它存储着一个内存地址,而引用是一个别名,它是已经存在的变量或对象的别名。因此,指针本身占据内存空间,而引用不占用内存空间。 指针和引用的自增(++)运算符意义不同,指针是对内存地址自增,而引用是对值的自增。 指针需要解引用,引用使用时无需解引用(*)。 指针可变,引用只能在定义时被初始化一次,之后不可变。 指针可以为空,引用不能为空。 “sizeof 指针”得到的是指针本身的大小,在32 位系统指针变量占用4字节内存,“sizeof 引用”得到的是所指向的变量(对象)的大小。 记忆:内增,可变空解S #include "stdio.h"int main(){ int x = 5; int *p = &x; int &q = x; printf("%d %d\n",*p,sizeof(p)); printf("%d %d\n",q,sizeof(q));}//结果5 8 5 4 由结果可知,引用使用时无需解引用(*),指针需要解引用;我用的是64位操作系统,“sizeof 指针”得到 的是指针本身的大小,及8个字节。而“sizeof 引用”得到的是的对象本身的大小及int的大小,4个字节。 33.为什么有了指针还需要引用 指针是一个变量,存储着内存地址,可以通过解引用操作符 * 来访问所指向的内存。指针可以为空(nullptr),可以被重新赋值指向其他对象,甚至可以指向无效的内存地址。指针的优势在于它的灵活性和动态性,可以动态分配和释放内存,以及实现数据结构和动态数据结构的设计。指针也可以作为函数参数进行传递,从而实现在函数内部修改实参的值。 引用是一个别名,它为现有的对象提供了一个新的名称。引用必须在声明时初始化,并且不能被重新赋值引用其他对象。引用在语法上与被引用的对象相同,可以像使用对象本身一样使用引用。引用的优势在于它的简洁性和安全性,它提供了一种直接访问对象的方式,不需要解引用操作,同时不会涉及指针的复杂性和潜在的错误。 尽管指针和引用都可以用于在函数之间传递参数和访问对象,但它们有一些区别和适用场景: 空值(null value):指针可以为空,即指向空地址(nullptr),而引用必须始终引用一个有效的对象。当对象可能不存在或需要表示空值时,可以使用指针。例如,当函数需要返回一个可能为空的结果时,可以使用指针作为返回值。 重新赋值:指针可以被重新赋值指向其他对象,而引用一旦初始化后就不能被重新赋值。如果需要在函数内部修改实参的值,可以使用指针作为函数参数;如果只需要访问对象而不修改它,可以使用引用。 安全性和简洁语义:引用在语义上表示对现有对象的别名,不会产生空指针或无效引用的问题,因此引用相对更安全。同时,引用语义更直观和简洁,可以使代码更易读和易懂。 因此,指针和引用在不同的情况下具有不同的用途。指针提供了更大的灵活性和动态性,适用于需要动态分配内存、重新赋值、或表示可能为空的对象的情况。引用提供了更简洁和直接的访问方式,适用于只需访问对象而不需要重新赋值的情况。根据具体的需求和语义,可以选择使用指针或引用来满足编程的要求。 34.指针和引用如何相互转换? 指针转引用:把指针用*就可以转换成对象,可以用在引用参数当中。 int a = 5; int *p = &a; void fun(int &x){}//此时调用fun可使用 : fun(*p); //p是指针,加个*号后可以转换成该指针指向的对象,此时fun的形参是一个引用值, //p指针指向的对象会转换成引用X。 引用转指针:把引用类型的对象用&取地址就获得指针了。 指针和引用之间如何转换?:question: 指针和引用之间的转换方式与对象之间的转换方式相似。可以使用以下方法进行转换: 将指向派生类对象的指针赋值给指向基类对象的指针是安全的,因为基类指针只能访问派生类对象的基类部分。将指向派生类对象的引用赋值给指向基类对象的引用也是安全的。 将指向基类对象的指针或引用转换为指向派生类对象的指针或引用,需要使用强制类型转换操作符(static_cast/dynamic_cast)。这种转换需要进行向下转型的安全检查。如果基类对象实际上是派生类对象,则向下转型成功。如果基类对象不是派生类对象,则向下转型失败,将导致未定义的行为。 35.函数调用时传入参数为引用、指针、传值的区别 传值 在传值方式中,函数会将参数的值复制一份,并在函数内部使用这份复制品。这意味着函数内部对参数的任何修改都不会影响函数外部的原始参数。 传指针 在传指针方式中,函数会接收参数的地址,也就是指向参数内存位置的指针。这意味着函数内部可以直接访问原始参数,并进行修改。 传引用 在传引用方式中,函数会接收参数的引用,也就是指向参数的别名。这意味着函数内部可以直接访问原始参数,并进行修改,就像传指针一样。但与传指针不同的是,我们在函数调用时不需要使用取地址符&来获取参数的地址,而是直接使用参数本身。 36.C++中的指针传参和引用传参底层原理你知道吗? 指针传参 本质上是值传递,它所传递的是一个地址值。 值传递过程中,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。 值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(形参指针变了,实参指针不会变)。如果改变被调函数中的指针地址本身,它将应用不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量(地址),那就得使用指向指针的指针或者指针引用。 如果修改指针指向的地址的值,那就和引用传参一样。 引用传参 本质上是值传递,它所传递的是一个地址值,是由主调函数放进来的实参变量的地址。(引用底层是指针常量,指针本身指向不可变,指向的值可变)被调函数的形式参数也作为局部变量在栈中开辟了内存空间。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。 从编译的角度来讲,程序在编译时分别将指针和引用添加到符号表上,符号表中记录的是变量名及变量所对应地址。 指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。 37.在传递函数参数时,什么时候该使用指针,什么时候该使用引用呢? 什么情况用指针当参数,什么时候用引用,为什么? 需要返回函数内局部变量的内存的时候用指针。使用指针传参需要开辟内存,用完要记得释放指针,不然会内存泄漏。而返回局部变量的引用是没有意义的 对栈空间大小比较敏感(比如递归)的时候使用引用。使用引用传递不需要创建临时变量,开销要更小 类对象作为参数传递的时候使用引用,这是C++类对象传递的标准方式 38.在进行函数参数以及返回值传递时,其中使用引用传参的好处有哪些? 在函数内部可以对参数进行修改 提高函数调用和运行的效率。因为没有了传值和生成副本的时间和空间消耗,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。 编程和阅读更清晰。使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差; 但是有以下的限制: 不能返回局部变量的引用。因为函数返回以后局部变量就会被销毁 不能返回函数内部分配的内存的引用。 可以返回类成员的引用,但是最好是const。因为如果其他对象可以获得该属性的非常量的引用,那么对该属性的单纯赋值就会破坏业务规则的完整性。 万能指针void* 39.void * 使用 void*可以指向任何类型的地址,但是带类型的指针不能指向void * 的地址 正常来说如果两个指针类型不一样的话,两个指针变量是不可以直接相等的。例如int* a, float* b,假如令a = b,会直接发生编译错误,而void * 指针可以等于任何类型的指针。但是反过来不可以,也就是说一个有类型的指针不能指向一个void类型的变量(哪怕此时void变量已经指向了一个有类型的地址)。 float f = 5.5;float* pf = &f;void* pv = pf;float* pf2 = pv; //编译错误,有类型的指针变量不能指向void*变量 void*指针只有强制类型转换以后才可以正常取值 int main(int argc, const char * argv[]) { float f = 5.5; float* pf = &f; void* pv; pv = pf; //这句是可以的 cout<<*pv<<endl; //编译错误,这样直接对pv取值是错误的 cout<<*(float*)pv<<endl; //强制类型转换后可以取值 return 0;} 在令pv = pf后,此时pv和pf指向的是同一个地址,值相同,但是两者的类型是不一样的。pf作为浮点型指针,是可以直接取到浮点数的,但是pv必须要强制类型转换以后才可以取值,也就是说一个void*的指针必须要经过强制类型转换以后才有意义。 int main(int argc, const char * argv[]) { float f = 5.5; float* pf = &f; void* pv; pv = pf; cout<<*(float*)pv<<endl; //强制类型转换后可以取值,值为5.5 cout<<*(int*)pv<<endl; //强制类型转换,值为1085276160 cout<<(int)(*(float*)pv)<<endl;//取值后再次类型转换,值为5 return 0;} 如果把一个指向float * 的值的void * 指针,强制转换成int*也是不对的。也就是说地址保存了什么样的变量,就要转化成哪种类型的指针,否则就会出错。 void*指针变量和普通指针一样可以通过等于0或者NULL来初始化,表示一个空指针 void* pv = 0; void* pv2 = NULL;cout<<pv <<endl; //值为0x0cout<<pv2<<endl; //值为0x0 当void * 指针作为函数的输入和输出时,表示可以接受任意类型的输入指针和输出任意类型的指针 如果函数的输入类型为void*,在调用时由于是值传递,所以函数实际接收到的应该就是一个地址值。这个值可以是任意类型。 void* test(void* a){ return a;} int main() { static int a = 5; int* pi = &a; cout<<pi<<endl; //值为0x100001060 cout<<test(pi)<<endl; //值为0x100001060 cout<<test((void*)pi)<<endl; //值为0x100001060 } 如果函数的输入类型为void*,在调用时由于是值传递,所以函数实际接收到的应该就是一个地址值。这个值可以是任意类型。 int a = 5;int* pi = &a; void* test(){ return pi; } int main() { cout<<test()<<endl; //值为0x100001060} 输出时同样也是值传递,因此可以输出任意类型指针指向的地址。 和void的区别 //返回了一个空指针void* say_hello(void* args){ cout << "Hello World!" << endl; return 0;} //没有返回值void say_hello(void* args){ cout << "Hello World!" << endl; return;} 其实两个函数实现的内容是一样的。但是void*返回类型的函数返回了一个空指针,而void型没有返回值。 40.void * 作用 函数传参时不确定类型,或者要支持多类型的传参; void function(int dataType, void* data) { // 根据dataType的不同值,进行不同的转换 switch (dataType) { case 0: int* a = (int*)data; case 1: char* a = (char*)data; ... }} 当函数的返回值不考虑类型指关心大小的时候 void * memcpy(void *dest, const void *src, size_t len);void * memset ( void * buffer, int c, size_t num ); memcpy和memset对外接收任何类型的指针,这样是合理并且必要的,因为这是内存操作函数,是对bit进行操作的,考虑数据类型是没有任何意义的。 int *a=NULL;a=(int *)malloc(sizeof(int));//返回的是void*,所以赋值给其他指针类型要强转一下 同样的,malloc函数只关注你要多大的内存,你需要把它怎么划分是你的事情,但是你需要显式的表明你是怎么划分的。这里语法要求是必须的,void *类型转为其他类型必须强制类型转换。 野指针 41.野指针是什么? 野指针是一种指针变量,它指向的内存地址已经不再被分配给该程序使用。 野指针通常会出现在以下情况下: 对未初始化的指针进行间接引用; 当指针被创建时,指针不可能自动指向NULL,这时,默认值是随机的,此时的指针成为野指针。 对已经释放的指针进行间接引用; 当指针被free或delete释放掉时,如果没有把指针设置为NULL,则会产生野指针(或叫悬空指针),因为释放掉的仅仅是指针指向的内存,并没有把指针本身释放掉。 对指向栈内存的指针在函数返回后进行间接引用; 下面有道题 42.如何避免野指针? 对指针进行初始化。 //将指针初始化为NULL。 char *p = NULL;//用malloc分配内存 char * p = (char * )malloc(sizeof(char)); //用已有合法的可访问的内存地址对指针初始化 char num[30] = {0}; char *p = num; malloc函数分配完内存后需注意: 检查是否分配成功(若分配成功,返回内存的首地址;分配不成功,返回NULL。可以通过if语句来判断) 清空内存中的数据(malloc分配的空间里可能存在垃圾值,用memset或bzero 函数清空内存) //s是需要置零的空间的起始地址; n是要置零的数据字节个数。 void bzero(void *s, int n); //如果要清空空间的首地址为p,value为值,size为字节数。 void memset(void *start, int value, int size); 指针用完后释放内存,将指针赋NULL delete(p); p = NULL; 43.野指针和悬空指针 都是是指向无效内存区域(这里的无效指的是"不安全不可控")的指针,访问行为将会导致未定义行为。 野指针 野指针,指针未初始化或已释放 int main(void) { int* p; // 未初始化 std::cout<< *p << std::endl; // 未初始化就被使用 return 0;} 因此,为了防止出错,对于指针初始化时都是赋值为 nullptr,这样在使用时编译器就不会直接报错,产生非法内存访问。 悬空指针 悬空指针,指针已释放但未置为 NULL 或者超出了其指向的内存区域 int main(void) { int * p = nullptr; int* p2 = new int; p = p2; delete p2;} 此时 p和p2就是悬空指针,指向的内存已经被释放。继续使用这两个指针,行为不可预料。需要设置为p=p2=nullptr。此时再使用,编译器会直接保错。 避免野指针比较简单,但悬空指针比较麻烦。c++引入了智能指针,C++智能指针的本质就是避免悬空指针的产生。 44.请问运行下面的Test()函数会有什么样的后果? char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf("%s\n", str); } 打印野指针内容,可能是乱码。 GetMemory()返回的是指向栈内存的指针,但该栈内存已被释放,该指针的地址不是 NULL,成为野指针,新内容不可知。 45.请问运行下面的Test()函数会有什么样的后果? void Test(void) { char *str = (char *) malloc(100); strcpy(str,"hello"); free(str); if(str != NULL) { strcpy(str, "world"); printf("%s\n", str); } } 篡改堆区野指针指向的内容,后果难以预料,非常危险。 free(str);之后,str成为野指针,没有置为NULL,if(str != NULL)语句不能阻止篡改操作。 智能指针 46.C++中的智能指针是什么? C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,使用
点赞 1
评论 0
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
昨天 11:05
长安大学 产品经理
去魅。去魅,对大厂狠狠去魅!
在北京某大厂实习了两个月,真的,每天都感觉好痛苦。实在不知道跟谁说,就跑这儿来念叨念叨吧。公司是传媒类的,我做的算是账号和内容运营这块儿。干过才知道,这活儿吧,说不上多“脏”,但也绝对没多有意思。最大的感受就是:这行真像在做巧克力流水线! 把别人的视频咔咔一顿剪,打上码,换个标题文案,嘿,就成了“我们的”内容了。以前刷微博还挺喜欢某些大V的,现在知道了,背后其实是一茬茬的实习生轮着班在运营。那些你以为很用心、有深度的博主,皮下可能也就是个实习生。在部门眼里,这些账号就是生意。稍微做点女性相关或者稍微尖锐点的内容,立马被毙,生怕“引起争议”,真的束手束脚。实习生在这儿就跟消耗品似的,今天这个走了...
我对___祛魅了
点赞
评论
收藏
分享
07-29 01:29
华南理工大学 演员/配音/模特
mentor:你是猪吗?
实习最崩溃瞬间——亲手写的代码和日志被无情删除,还被骂是猪。本人实习写过一份代码,里面有两份日志(存放在mentor指定的路径下面),记录了每一条被处理过的数据。然后我昨天做另一个方案的时候,需要用到我之前保存到的日志,我就写《将之前的日志信息作为这次的输入》,因为我记得很清楚,只要之前有处理数据,那就一定有日志,而且有两份。mentor看了我的方案以后,以下是我和mentor的对话:mentor:“你是猪吗?你太爱想当然了,什么都假设最理想的情况,你哪来的日志。”我:“上一份代码是我写的,我确认有保存了日志”mentor:“为什么确认”?我:“因为代码是我写的,我还check过日志”ment...
食堂在逃干饭王:
那你往mt身上拱啊
如何快速融入团队?
点赞
评论
收藏
分享
06-12 17:11
湖南师范大学 算法工程师
电子科学与技术 暑期实习0offer,简历修改,不玻璃心
研究生两年都在干科研,研究生方向很偏,项目不大对口,至今0offer
点赞
评论
收藏
分享
07-09 20:24
湖北师范大学 Java
27届投日常实习
打算再背一两周的八股就开始投一下实习,简历目前准备的是这样的,求各位牛友看看还有啥需要完善的地方没
程序员小白条:
找个实习没啥问题的,海投吧
点赞
评论
收藏
分享
07-29 12:11
安徽大学 Java
京东方一面
电话面,挺突然的,还没进入面试状态呢主要是简历深挖,针对项目细节提问,然后反问我感觉视频面反而更自然
京东方一面24人在聊
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
点赞
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
都是 dirty work,为什么别人的简历上就能言之有物🤔
1.2W
2
...
滴滴提前批
9237
3
...
实习都是CRUD怎么包装
8557
4
...
百度提前批一面(秋招第一场也估计是压力最大的)
7460
5
...
秋招首凉-腾讯TEG 云架构平台提前批
5938
6
...
【07.29更新】能救一个是一个!26届毁意向毁约裁员黑名单
5351
7
...
字节懂车帝 后端实习一面
3443
8
...
团孝子启动ing!
3251
9
...
干活最少的实习生因为长得漂亮转正了
3155
10
...
面试劫匪??????
2956
创作者周榜
更多
正在热议
更多
#
26届的你,投了哪些公司?
#
16936次浏览
205人参与
#
我对___祛魅了
#
27299次浏览
266人参与
#
中兴秋招
#
194186次浏览
2171人参与
#
你最讨厌面试问你什么?
#
11363次浏览
168人参与
#
你跟室友的关系怎么样?
#
3038次浏览
59人参与
#
工作中哪个瞬间让你想离职
#
45480次浏览
401人参与
#
简历上的经历如何包装
#
11061次浏览
347人参与
#
你遇到最难的面试题目是_
#
4101次浏览
78人参与
#
如何快速融入团队?
#
9726次浏览
120人参与
#
和同事相处最忌讳的是__
#
13264次浏览
137人参与
#
通信/硬件求职避坑tips
#
85988次浏览
868人参与
#
什么样的背景能拿SSP?
#
15227次浏览
122人参与
#
毕业后不工作的日子里我在做什么
#
190238次浏览
1633人参与
#
应届生应该先就业还是先择业
#
124836次浏览
695人参与
#
字节跳动工作体验
#
458367次浏览
4625人参与
#
如何排解工作中的焦虑
#
190535次浏览
1958人参与
#
多益网络求职进展汇总
#
30948次浏览
138人参与
#
总结:哪家公司面试体验感最差
#
63229次浏览
287人参与
#
元戎启行求职进展汇总
#
35963次浏览
278人参与
#
我和mentor的爱恨情仇
#
61793次浏览
378人参与
#
实习生活中那些难忘的瞬间
#
164082次浏览
2439人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务