c++常见面试知识点(一)

  • 指针和引用的区别
1.指针:一个变量,存储的内容为一个地址;引用:给一个已有对象起的别名
2.指针是一个实体,需要分配内存空间;引用只是变量别名,不需要分配内存空间
3.可以有多级指针,不能有多级引用
4.自增运算结果不一样
5.指针是间接访问,引用是直接访问
6.指针可以不用初始化,引用一定要先初始化
  • struct和class区别
1.struct默认防控属性是public的,而class默认的防控属性是private的
2.在继承关系,struct默认是public的,而class是private
3.class这个关键字还可用于定义模板参数,但是strcut不用与定义模板参数
  • " "和<>的区别
1." "会从当前路径搜寻而<>会从标准文件的路径寻找
  • c++结构体和c结构体区别
1、C中结构体不能有成员函数,而C++中可以有,甚至可以有虚函数。所以C中不存在构造函数、虚构函数和this指针。
2、C结构体只有public一种权限,而C++结构体有public、private、protect三种权限。
3、C结构体没有继承关系,而C++结构体可以从类或者其他结构体继承而来。
4、C结构体不能在结构体中初始化成员变量,而C++结构体可以。
5、C结构体不能有静态成员变量,而C++结构体可以有。
  • 指针和数组的区别
数组对应着一块内存
指针是指向一块内存
数组的地址和空间大小在生命周期不会发生改变,而指针指向的内存大小可以随时发生改变。
当指针指向常量字符串的时候,它的内容不可以改变。
计算容量的区别:用sizeof计算出数组元素个数,无法计算指针所指向内存的大小
数组名是常量指针,指针是变量指针
对数组用&和对指针用&的意义不同,此时数组名不在当成指向一个元素的常量指针来使用
int a[10]={0};  
其中a=&a[0];
  • sizeof和strlen区别
sizeof计算大小int a[5]可以看成类型是int[5]1.sizeof是运算符strlen是函数
2.strlen计算指定字符串str的长度,但不包括结束字符即null字符,正因为它为函数,所以需要一次函数调用
3.strlen函数原型:size_t strlen(char const*str)函数返回值为size_t类型,size_t类型为无符号整型,所以if(strlen(x)-strlen(y)>=0)和if(strlen(x)>=strlen(y))有很大区别。
4.sizeof是一个单目运算符,在编译时就计算好了,由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小
练习题:
1. char p2[] = "hello\\0";p2 的结果:p2=hello\0,strlen=7,sizeof=8
第一个\转义了紧挨着的\,使得后面0只是一个普通字符,不能与前面/成为整体。即strlen(hello\0A)=7,sizeof(hello\0A)=8
2. char p3[] = "hello\\\0";p3 的结果:p3=hello\,strlen=6,sizeof=8
第一个\只转义了第二个\,使得第二个\不能再转义后面,所以第三个/与0成为整体并有结束计算的作用。即p3=hello\AA
3. char p4[] = "hel\0lo";p4 的结果:p4=hel,strlen=3,sizeof=7
strlen碰到\0就停止输出和计算,所以结果是3;但sizeof不会停止而且两个\0都计算,即sizeof计算helAloA
4. char p5[] = "hel\\0lo";p5 的结果:p5=hel\0lo,strlen=7,sizeof=8
第一个\转义了紧接的\,使得后面0只是普通字符,而sizeof比strlen多计算一个\0。即计算的p5=hel\0loA
  • 函数指针和指针函数
函数指针的应用场景:回调(callback)。我们调用别人提供的 API函数(Application Programming Interface,应用程序编程接口),称为Call;如果别人的库里面调用我们的函数,就叫Callback。
//以库函数qsort排序函数为例,它的原型如下:
void qsort(void *base,//void*类型,代表原始数组
           size_t nmemb, //第二个是size_t类型,代表数据数量
           size_t size, //第三个是size_t类型,代表单个数据占用空间大小
           int(*compar)(const void *,const void *)//第四个参数是函数指针
          );
//第四个参数告诉qsort,应该使用哪个函数来比较元素,即只要我们告诉qsort比较大小的规则,它就可以帮我们对任意数据类型的数组进行排序。在库函数qsort调用我们自定义的比较函数,这就是回调的应用。
//示例
int num[100];
int cmp_int(const void* _a , const void* _b){//参数格式固定
    int* a = (int*)_a;    //强制类型转换
    int* b = (int*)_b;
    return *a - *b;  
}
qsort(num,100,sizeof(num[0]),cmp_int); //回调
指针函数
指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。
声明格式为:*类型标识符 函数名(参数表)
int *fun(int x,int y);
  • c++传值方式
1.值传递:形参即使在函数体内值发生变化,也不会影响实参的值;
2.引用传递:形参在函数体内值发生变化,会影响实参的值;
3.指针传递:在指针指向没有发生改变的前提下,形参在函数体内值发生变化,会影响实参的值;
  • 静态变量什么时候初始化
对于C语言的全局和静态变量,初始化发生在任何代码执行之前,属于编译期初始化。而C++标准规定:全局或静态对象当且仅当对象首次用到时才进行构造。
  • 野指针
野指针是指向位置随机的、不正确的指针,系统无法对其进行操作;
产生原因:
1、创建指针时没有对指针进行初始化,导致指针指向一个随机的位置;
2、释放指针指向的内存后没有置空,从而指向垃圾内存;
3、在超越变量作用域下使用指针,如:在栈内存被释放之后,指向栈内存的指针会指向垃圾内存;
  • 内联函数和宏函数区别
c++宏定义:
(1)简单的宏定义:
#define <宏名><字符串>
eg:#define PI 3.14;
Folat pi2=PI*2=6.28;
(2) 带参数的宏定义
#define <宏名> (<参数表>) <宏体>
例: #define AddOne(x) (x+1)
float pi2 = PI * 2;//pi2 = 6.28
 pi2 = AddOne(pi2);// pi2 = 7.28
宏替换发生的时机
(1)文件包含
  可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
(2)条件编译
预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。
(3)宏展开
预处理器将源程序文件中出现的对宏的引用展开成相应的宏定义,即本文所说的#define的功能,由预处理器来完成。经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。
宏定义的特点
(1)宏名一般用大写,且末尾不加分号。
(2)宏定义的参数是无类型的,不做语法检查,不做表达式求解,只做替换。
(3)宏定义通常在文件的最开头,可以使用
(4)宏定义可以嵌套,但字符串” “中永远不包含宏。
(5)宏展开使源程序变长,函数调用不会;宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)。
(6)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存。
(7)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义,常量pi常用宏定义。
1、编译器会对内联函数的参数类型做安全检查或自动类型转换,而宏定义则不会,他只是进行单纯的文字替换,不会做任何类型的检查
2、内联函数在运行时可调试,而宏定义不可以。
3、内联函数可以访问类的成员变量,宏定义则不能
4、在类中声明同时定义的成员函数,自动转化为内联函数。
  • C++从代码到可执行二进制文件的过程
**预编译:这个过程主要的处理操作如下:**
1.将所有的#define删除,并且展开所有的宏定义
2.处理所有的条件预编译指令,如#if、#ifdef
3.处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。
4.过滤所有的注释
5.添加行号和文件名标识。
**编译:这个过程主要的处理操作如下:**
1.词法分析:将源代码的字符序列分割成一系列的记号。
2.语法分析:对记号进行语法分析,产生语法树。
3.语义分析:判断表达式是否有意义。
4.代码优化:
5.目标代码生成:生成汇编代码。
6.目标代码优化:
**汇编:这个过程主要是将汇编代码转变成机器可以执行的指令。**
**链接:将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序。**
链接分为静态链接和动态链接。
静态链接,是在链接的时候就已经把要调用的函数或者过程链接到了生成的可执行文件中,就算你在去把静态库删除也不会影响可执行程序的执行;生成的静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。
而动态链接,是在链接的时候没有把调用的函数代码链接进去,而是在执行的过程中,再去找要链接的函数,生成的可执行文件中没有函数代码,只包含函数的重定位信息,所以当你删除动态库时,可执行程序就不能运行。生成的动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。
  • const关键字
const修饰全局变量
const修饰局部变量
const修饰指针,const int * 
const修饰指针指向的对象,int * const
const修饰引用左形参
const修饰成员变量,必须在构造函数列表中初始化
const修饰成员函数,说明该函数不应该修改非静态成员,但是这并不可靠,指针
所指的非成员对象值可能会被改变
指针常量——指针类型的常量(int *const p)
本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。
常量指针:如果在定义指针变量的时候,数据类型前用const修饰,被定义的指针变量就是指向常量的指针变量,指向常量的指针变量称为常量指针,格式如下
const int *p = &a; //常量指针
因为常量指针本质是指针,并且这个指针是一个指向常量的指针,指针指向的变量的值不可通过该指针修改,但是指针指向的值可以改变。
  • static关键字
static:
局部静态变量:static局部变量和普通局部变量有什么区别?
普通局部变量与static局部变量的区别
内存分配和释放
1、普通局部变量只有执行到变量定义的语句的时候才分配空间。
2、static局部变量在编译阶段(函数还没有执行),变量的空间已经分配。
3、普通局部变量离开作用域{},自动释放其空间,也就无法使用此变量。
4、static局部变量只有在整个程序结束的时候才将其自动释放。
初始化
1、普通局部变量如果不初始化,为随机值。
2、static局部变量如果不初始化,为0。
3、static局部变量初始化语句只有第一次执行时有效,但是可以赋值多次。
4、static局部变量只能用它常量初始化。
全局静态变量:static全局变量与普通变量有什么区别?
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。
这两者的区别虽在于非静态区全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其他源文件中不能使用它。
由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数用,因此可以避免在其他源文件中引用错误。
把局部变量改为静态变量后是为了改变它的存储方式即改变了它的生存周期。把全局变量改为静态变量后是什么改变了它的作用域,限制了它的使用范围。
static全局变量与普通的全局变量有什么区别:static全局变量只初始化一次,防止在其他文件单元中被引用。
静态成员函数:static函数与普通函数有什么区别?
static函数与普通函数作用域不同,仅在本文件中。只在当前源文件中使用函数应该说明为内部函数(static),内部函数应该在当前源文件中说明,要使用这些函数的源文件要包哦含这个头文件,static函数与普通函数的区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
  • define和inline
define和inline
	本质:define只是字符串替换,inline由编译器控制
	内联函数在编译时展开,而宏是由预处理器对宏进行展开
	内联函数会检查参数类型,宏定义不检查函数参数,所以内联函数会更加安全。
	宏不是函数,而inline函数是函数
宏在定义时要小心处理宏函数(一般情况把参数用括号括起来)
  • define的typedef
#define是预处理命令,在预处理是执行简单的替换,不做正确性检查。
typedef是在编译时期处理的,它是在自己的作用域内给已经存在的类型一个别名。
  • new和malloc
1.new是运算符,malloc是C语言函数库
2.new可以重载,malloc不能重载
3.new的变量是数据类型,malloc是字节大小
4.new可以调用构造函数,delete可以调用析构函数。malloc/free不能。
5.new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回一般都需要进行类型转换。
6.malloc分配的内存不够的时候可以使用realloc扩容,new没有这样的操作。
7.new内存分配失败抛出bad_malloc,malloc内存分配失败返回NULL值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值