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) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...
随机推荐
- @media screen页面自适应尺寸!!
@media screen and (max-width:360px){body,input,select{font-size:38%}} @media screen and (min-width:3 ...
- Equation
You are given an equation: Ax2 + Bx + C = 0. Your task is to find the number of distinct roots of th ...
- JSONP原理及实现跨域方式
今天做页面时,后台给了个接口:https://a.a.com/a/a.json,我页面的上线地址是:http://b.b.com.显而易见,因为浏览器同源策略的限制,通过ajax无法无法取得json的 ...
- 继《关于讯飞语音SDK开发学习》之打包过程中遇到小问题
关于讯飞语音SDK开发学习 使用vs自带打包,具体怎么操作就不说了,网上关于这方面的资料挺多的.例如:winform 打包部署,VS2010程序打包操作(超详细的),关键是桌面上创建快捷方式中的&qu ...
- 学习动态性能表(10)--v$session_longops
学习动态性能表 第十篇--V$SESSION_LONGOPS 2007.6.7 本视图显示运行超过6秒的操作的状态.包括备份,恢复,统计信息收集,查询等等. 要监控查询执行进展状况,你必须使用cos ...
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...
- wpf控件提示Value ‘’ can not convert
我们在对控件的ErrorTemplate设置后,有时会出现Value '' can not convert. 为什么会出现呢? 原因:如果控件的输入值和null不能转换(比如控件要求的是int或flo ...
- [MySQL-MM] 生产环境自动恢复MM中一台M2库的过程,分享从零开始写的自动化重建脚本以及思路 (转)
必须是MM架构,而且一台主库M1是完好无损的,一台主库M2可以根据M1主库来进行重建:如果MS架构,自己可以稍微做一下脚本修改动作,也能使用,架构如下图所示: 3 总体思路,建立主脚本a_build ...
- Runnable、Callable、Future和FutureTask之一:基本用法
Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线程编程简单直接.但正如之前提到过的,Thre ...
- C++面试考点
1.下面程序在x64下结果 struct st { int a; long long b; double c; }; int main() { st s; cout << &s.a ...