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) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...
随机推荐
- [独孤九剑]Oracle知识点梳理(三)导入、导出
本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...
- Python函数-cmp()
cmp(x, y) 作用: 比较两个对象x和y,如果x < y ,返回负数:x == y, 返回0:x > y,返回正数. 注:在python2所有版本中都可用,但在pyt ...
- Xml日志记录文件最优方案(附源代码)
Xml作为数据存储的一种方式,当数据非常大的时候,我们将碰到很多Xml处理的问题.通常,我们对Xml文件进行编辑的最直接的方式是将xml文件加载到XmlDocument,在内存中来对XmlDocume ...
- Linux驱动多线程 - 互斥量
1.内核多线程相关内容 1.1 头文件#include <linux/kthread.h> 1.2 定义/初始化变量 struct mutex SPI_work; /*定义互斥体*/ mu ...
- HTML5通信
跨文档消息传输 HTML5中提供了在网页文档之间互相接收与发送信息的功能.使用这个功能只要获取到网页所在窗口对象的实例,无论是否同源都可以实现跨域通信.经常用于不同frame之间的通信. 当我们想要接 ...
- 机器学习:模型泛化(LASSO 回归)
一.基础理解 LASSO 回归(Least Absolute Shrinkage and Selection Operator Regression)是模型正则化的一定方式: 功能:与岭回归一样,解决 ...
- java流类练习前篇
总结: package com.aini; import java.io.*; public class gf { public static String main(String[] args) t ...
- select *和select 全部
select *和select 全部字段 在查询上效果是一样的,速度也是一样的. 不过理论上来说select *反而会快点. 因为 1.select 全部字段在数据传输上消耗会更多,如果几百个字段这个 ...
- JCTF 2014(Reverse)
小菜一碟: 点击下载附件 下载的附件没有后缀,用c32打开看看 是apk文件,用Smali2JavaUI打开 程序把输入框的字符串反转,然后进行MD5加密,最后进行base64编码,与NzU2ZDJm ...
- 2016.8.17服务器端数据库用户导入导出方法 expdp和impdp
EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用,不能在客户端使用. IMP只适用于EXP导出的 ...