C++面试笔记--指针和引用
面试一:指针与引用的区别?
答案:
(1)非空区别。在任何情况下都不能使用指向空值的引用。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针要高。
(2)合法性区别。在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。
(3)可修改区别。指针与引用的另一个重要的区别是指针可以被重新赋值以指向另一个不同对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变,但是指定的对象其内容可以改变。
面试题二:下面5个函数哪个能成功进行两个数的交换?
#include<iostream>
using namespace std;
void swap1(int p,int q)
{
int temp;
temp=p;
p=q;
q=temp;
}
void swap2(int *p,int *q)
{
int *temp;
*temp=*p;
*p=*q;
*q=*temp;
}
void swap3(int *p,int *q)
{
int *temp;
temp=p;
p=q;
q=temp;
}
void swap4(int *p,int *q)
{
int temp;
temp=*p;
*p=*q;
*q=temp;
}
void swap5(int &p,int &q)
{
int temp;
temp=p;
p=q;
q=temp;
}
int main ()
{
int a=,b=;
//swap1(a,b);
//swap2(&a,&b);
//swap3(&a,&b);
//swap4(&a,&b);
//swap5(a,b);
cout << "a:"<< a <<endl;
cout << "b:"<< b <<endl;
return ;
}
解析:这道题考察的是参数传递、值传递、指针传递(地址传递)和引用传递。
swap1传递的是值的副本,在函数中只是修改了形参p、q(实际是a、b的一个拷贝),p、q的值确实交换了,但是它们是局部变量,不会影响到主函数a和 b 。当函数swap1生命周期结束时,p、q所在的栈也就被删除了。
swap2传递的是一个地址进去,在函数体内的形参*p、*q是指向实际的参数a、b地址的两个指针。
这里要注意:
int *temp;
*temp=*p;
是不符合逻辑的,int *temp新建了一个指针(但是没分配内存)。*temp=*p不是指向而是拷贝。把*p所指向的内存的值(也就是a 的值)拷贝到*temp所指向内存里了。但是int *temp不是不分配内存吗?的确不分配,于是系统在拷贝时临时给了一个随机地址,让它存值。分配的随机地址是个“意外”,且函数结束后不回收,造成内存泄漏。
swap3传递的是一个地址,在函数体内的参数*p、*q是指向实际参数a、b地址的两个指针。
这里要注意:
int *temp;
temp=p;
int *temp新建了一个指针(但是没分配内存)。temp=p是指向而不是拷贝。temp指向了*p所指向的地址(也就是a )。而代码:
int *temp;
q=temp;
但是函数swap3不能实现两数的交换,这是因为函数体内只是指针的变化,而对地址中的值却没有变化。
swap4可以实现两数的交换,因为它修改的是指针所指向地址中的值。
swap5函数与swap4相似,是一个引用传递,修改的结果直接影响实参。
答案:
swap3,swap5
面试题三:下面这个程序测试会有什么结果?
#include<iostream>
using namespace std;
void GetMemory(char *p,int num)
{
p=(char *)malloc(sizeof(char) * num);
}
int main ()
{
char *str = NULL;
GetMemory(str,);
strcpy(str,"hello");
return ;
}解析:毛病出在函数GetMemory中,编译器总是要为函数的每个参数制作临时副本,在本例中,void GetMemory(char *p , int num)中的*p实际上是主函数中str的一个副本,而在函数GetMemory中只是把p所指向的内存地址改变了,但是str丝毫未变,因为函数GetMemory没有返回值,因此str并不指向p所申请的那段内存,所以函数GetMemory并不能输出任何东西,如下图所示。事实上,每次执行一次GetMemory就会申请一块内存,但是申请的内存却不能有效释放,结果是内存一直被独占,最终造成内存泄露。

- 如果一定要用指针去申请内存,那么应该采用指向指针的指针,传str 的地址给函数GetMemory。代码如下:
#include<iostream>
using namespace std;
void GetMemory(char **p,int num)
{
*p=(char *)malloc(sizeof(char) * num);
}
int main ()
{
char *str = NULL;
GetMemory(&str,);
strcpy(str,"hello");
cout << *str << endl;
cout << str << endl;
cout << &str << endl;
return ;
}这样的话程序就可以运行成功了,我们分别打印 *str 、 str 、 &str 可以发现,结果分别是 h 、 hello 、 0024FA80 。str就是字符串的值;*str 是字符串首字符,&str 就是字符串的地址值。
当然也可以用函数返回值来传递动态内存。这种方法更简单,代码如下:
#include<iostream>
using namespace std;
char *GetMemory(char *p,int num)
{
p=(char *)malloc(sizeof(char) * num);
return p;
}
int main ()
{
char *str = NULL;
str = GetMemory(str,);
strcpy(str,"hello");
cout << *str << endl;
cout << str << endl;
cout << &str << endl;
return ;
}
- 如果一定要用指针去申请内存,那么应该采用指向指针的指针,传str 的地址给函数GetMemory。代码如下:
面试题四:这个函数有什么问题?该如何修改?
char *strA()
{
char str[] = "hello world";
return str;
}解析:这个str里存在的地址是函数strA栈里“hello world”的首地址。函数调用完成,栈帧恢复调用strA之前的状态,临时空间被重置,堆栈“回缩”,strA栈帧不再属于应该访问的范围。这段程序可以正确输出结果,但是这种访问方法违背了函数的栈帧机制。
但是只要另外一个函数调用的话,你就会发现,这种方式的不合理及危险性。
如果想获得正确的函数,改成下面这样就可以:
char *strA()
{
char *str = "hello world";
return str;
}首先要搞清楚char *str 和 char str[] :
1charstr[] ="hello world";是分配一个局部数组。局部数组是局部变量,它所对应的是内存中的栈。局部变量的生命周期结束后该变量不存在了。
1char*str ="hello world";是指向了常量区的字符串,位于静态存储区,它在程序生命期内恒定不变,所以字符串还在。无论什么时候调用 strA,它返回的始终是同一个“只读”的内存块。
另外想要修改,也可以这样:
12345char*strA(){staticcharstr[] ="hello world";returnstr;}通过static开辟一段静态存贮空间。
面试题五:写出下面程序运行的结果。
#include<iostream>
using namespace std;
int main ()
{
int a[];
a[]=; a[]=; a[]=;
int *p , *q;
p=a;
q=&a[];
cout << a[q-p] <<endl;
}解析:本程序的结构如下:
(1)先声明了一个整型数组a[3],然后分别给数组赋值。
(2)又声明了两个整型指针 p、q,但是并没有定义这两个指针所指向的地址。
(3)使整型指针 p 的地址指向 a(注意 a 就是a[0]),使整型指针 q 的地址指向 a[2]。
可实际验证程序如下:
#include<iostream>
using namespace std;
int main ()
{
int a[];
a[]=; a[]=; a[]=;
int *p , *q;
p=a;
cout << p <<endl;
cout << *p <<endl;
q=&a[];
cout << q <<endl;
cout << *q <<endl;
cout << a[q-p] <<endl;
}上面的输出结果分别是:
002DFD24
0
002DFD2C
2
2
2
q 的实际地址是 002DFD2C,p 的实际地址是 002DFD24。 002DFD2C-002DFD24=0x08(十六进制减法),相差是 8。
q-p的实际运算是(q的地址值(002DFD2C)- p的地址值(002DFD24))/sizeof(int),即结果为 2 。
面试题六:写出函数指针,函数返回指针,指向const的指针,指向const的const指针,const指针
void (*f)();//f是一个指向函数的指针变量,它可以代替这个函数例如: int c;c=(*f)(a,b);或者int max(a,b);int (*f)(a,b);p=max;--这里*P指向了max的开端,所以*p也变成了max函数了。
void * f();
const int * a;
const int *const a;
int *const a;指针数组和数组指针
a是指针数组,是指一个数组里面都装着指针。例如:int *ptr[].
b是一个数组指针,是指指向一个数组的指针。例如:int (*a)[3];
C++面试笔记--指针和引用的更多相关文章
- C++学习笔记 指针与引用
指针与引用 1. 指针 (1) 指针是一个变量(实体),存储的是一个地址,指向内存的一个存储单元,指针可以为空 (2) 指针可以为空,在声明定义时可以不初始化 (3) 指针在初始化之后可以重新指向其 ...
- C++学习笔记(五):指针和引用
声明指针: //指针声明 * 号左右的空格是可选的,下面的定义都是正确的 int *pointer1; int* pointer2; int*pointer3; int * pointer4; //注 ...
- 【校招面试 之 C/C++】第13题 C++ 指针和引用的区别
1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元:而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已.如: int ...
- 21天学通C++学习笔记(八):指针和引用
1. 简述 C++最大的优点之一是,既可以用它来编写不依赖于机器(主要是内存)的高级应用程序,又可以用它来编写与硬件紧密协作的应用程序. 事实上C++让您能够在字节和比特级调整应用程序的性能,而要编写 ...
- C++学习笔记30,指针的引用(2)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/guang_jing/article/details/32910093 能够创建不论什么类型的引用,包 ...
- 面试问题之C++语言:C++中指针和引用的区别
转载于:https://blog.csdn.net/gcc2018/article/details/82285940 1.指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元:而引用 ...
- c++指针与引用问题
本来是回答问题的,到这里做个笔记 *&L是指针的引用,实参是个指针.所以L是实参指针的别名,对别名L的修改,等于对实参的修改.*L是传值,你无法改变传过来的实参指针变量的值程序代码: #inc ...
- c++/java/c# 几种编程语言的指针、引用比较
前一段时间,我在 cnblogs 别人的博客中,谈到: java 中的引用/指针,与 c++/C# 中的引用/指针不是一个概念. Java 引用,相当于 c++ 指针(fun3).Java 引用可以赋 ...
- 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail
面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...
随机推荐
- Agc007_C Pushing Balls
传送门 题目大意 在一条直线上有$N$个球和$N+1$个洞,每两个球之间有一个洞,每两个洞之间有一个球,最左端和最右端都是洞,其中产生的$2N$个间隔满足从左到右是等差数列.你每次随机选择一个未被推进 ...
- HDU - 5977 Garden of Eden (树形dp+容斥)
题意:一棵树上有n(n<=50000)个结点,结点有k(k<=10)种颜色,问树上总共有多少条包含所有颜色的路径. 我最初的想法是树形状压dp,设dp[u][S]为以结点u为根的包含颜色集 ...
- Shiro-Session
概述 Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理.会话事件监听.会话存储/持久化.容器无关的 ...
- 洛谷 P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper
题目描述 A little known fact about Bessie and friends is that they love stair climbing races. A better k ...
- Yii查看(输出)当前页面执行的sql语句(log记录)
在Yii框架下查看当前页面执行的所有sql语句的方法,主要是通过配置相关文件来达到调试sql的目的,具体方法如下: (1)修改 index.php 开启调试模式 在 index.php 文件内增加如下 ...
- 详解Top命令 输出命令行选项及代码
Linux中的top命令显示系统上正在运行的进程.它是系统管理员最重要的工具之一.被广泛用于监视服务器的负载.在本篇中,我们会探索top命令的细节.top命令是一个交互命令.在运行top的时候还可以运 ...
- BZOJ4170:极光
浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html 题目传送门:https://lydsy.com/JudgeOnline/problem.p ...
- 使用PHP的GD2裁剪 + 缩放图片
/** * 裁剪 + 缩放图片 * @param array $params 包含x,y,width,height,path * @return string */ public function t ...
- Rails:rails链接多个数据库【转】
之前查到Rails应用中连接多个数据库的方式如下: class Cookie < ActiveRecord::Base establish_connection :typo ... end 这样 ...
- IDEA 运行spingboot时出现Process finished with exit code -1073741819 (0xC0000005)
经过多方查证,问题最终定位在金山词霸2016上,如果开启了金山词霸的取词和划意功能,就会出现此错误,估计是冲突吧. 解决办法:关掉金山词霸,或者把金山词霸的取词和划意功能关掉.经过尝试,发现只要在ID ...