C/C++常见考点

1、const:限定变量不允许修改,或者理解为只读变量。
const int a; //a是一个常整型变量
int const a; //a是一个常整型变量
const int *a; //a是一个指向常整型的指针,意味着a是一个指向可变的指针,但是a指向的整型数不可修改
int const *a; //a是一个指向整型的常指针,意味着a的指向不可变,但是a指向的整型数可以修改
int const *a const; //a是一个指向常整型的常指针,a的指向不可变,a指向的整型数也不可修改

2、指针数组和数组指针
指针数组:一个元素都是指针的数组,或者说是存储指针的数组
数组指针:一个指向数组的指针
int *p1[10]; //指针数组
int (*p2)[10]; //数组指针
分析:[]的优先级比*高,所以p1[10]表示一个包含十个元素的数组,int *表示该数组的元素类型为int型的指针。()的优先级比[]高,所以(*p2)表示一个指针,该指针指向一个包含十个int型元素的数组。
图解:

使用方法:
int a[5] = {1,2,3,4,5}; //初始化一个数组a
int (*p2)[5] = &a; //初始化数组指针p2,指向数组a的首地址
int i;
for(i = 0; i < 5; i++){
    printf("%d ", (*p2)[i]); //循环遍历打印每个元素
}

3、为什么c++代码调用c编译器编译的函数要加上extern C声明?
函数和变量被C++编译器编译后在符号表中名字与C语言的不同,导致C++程序不能直接调用C函数,为了解决这个问题,C++提供了一个extern C来修饰函数和变量,这些函数和变量会按照C语言的方式编译和链接,保证能够找到正确的符号。

4、inline和宏定义的区别
inline:内联函数是在编译的时候已经做好将对应的函数代码替换嵌入到对应的位置,适用于代码较少的函数。
宏定义:简单的字符串替换,如果定义的是有参数的函数形式,参数不做类型校验。

5、static
static全局变量:test.c文件定义的static全局变量,只能在对应的test.h和test.c文件中使用,不能在其他的.c文件中使用
static局部变量:同上,但是局部变量定义在函数中,只能这个函数内部使用,不能在相同.c文件的其他函数中使用
static函数:类似于c++类的private函数,一个源文件中的static函数对其他源文件是不可见的

6、指针和引用
相同点:
都是地址,指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
不同点:
指针是一个实体,而引用仅是个别名;
引用只能在定义时被初始化一次,之后不可变;指针可变;
引用不能为空,指针可以为空;
“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
指针和引用的自增(++)运算意义不一样;
引用是类型安全的,而指针不是 (引用比指针多了类型检查)

引用的两个主要用途:作为函数参数以及从函数中返回左值
传引用主要是它不生成临时变量,不进行返回值copy等,速度快
即使你传递的是指针,也只能修改指针指向的内容,不能修改指针本身。  
如果要修改当前被传递的参数的话,要么再加一级指针,要么用引用。

7、函数传值方式
1、值传递
2、指针传递
3、引用传递
swap函数的实现:
void swap2(int *a, int *b)
{
        int tmp = *a;
        *a = *b;
        *b = tmp;
}

void swap3(int &a, int &b)
{
        int tmp = a;
        a = b;
        b = tmp;
}

调用:
a = 3;
b = 10;
swap2(&a, &b);
swap3(a, b);

8、类和struct的区别
表面看,struct默认是public,而class默认是private。
更深层次上:两者最大的区别就在于思想上,c语言编程单位是函数,语句是程序的基本单元。而C++语言的编程单位是类。从c到c++的设计由过程设计为中心向以数据组织为中心转移。

9、变量的声明和定义
声明:指定变量的名字和类型,不会分配存储空间
定义:定义是对声明的扩展,会为变量分配存储空间,同时还可以指定初始值
extern:声明一个变量,同时表明定义在别处

10、sizeof运算符
sizeof不是函数,是一种运算符。假设系统为32位:
1、sizeof(int) -> 4;sizeof(char) -> 1
2、int *p; sizeof(p) -> 4
3、int a[] = {1,2,3,4};sizeof(a) -> 16 == 4 * 4
4、void func(int a[]){sizeof(a) --> 4};数组作为函数参数,自动转换为指针
5、空类(class/struct) -> 1
6、类内部使用自动填充,不足最小长度自动填充为最小长度的整数倍
7、类内部的static数据成员和成员函数不占空间
8、虚函数额外增加一个指针大小空间,因为存在一个虚机类表,会生成一个指针指向该表


11、#include<>和#include""的区别
前者从标准库路径搜索头文件,后者从当前工作路径搜索头文件

12、如何初始化一个字符数组,指针数组

数组的初始化就是定义一个数组并为数组中的每个元素赋值。
数组的初始化方式:
1、char a[10] = {"hello"}; //系统自动填充后几个未初始化的元素为'\0'

2、char b[10] = {'h','e','l','l','o','\0'}; //必须手动添加结束的'\0'

3、char c[] = {1,2,3,4,5}; //可以省略字符串长度

4、用sizeof运算符求数组元素个数:int a[] = {1,2,3,4,5}; len = sizeof(a)/sizeof(int);

5、省略数组长度只能在有初始化的数组定义中使用。错误的定义方式:int a[];

6、使用指针数组必须初始化。通常使用for循环完成初始化:
int a[5] = {1,2,3,4,5};
int *p[5];
for(i = 0; i < 5; i++){
p[i] = &a[i];
}
二维指针数组初始化:
int a[5][5]={1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5};
int *p[5]=[a[0],a[1],a[2],a[3],a[4]};

13、内存的分配方式
栈区:存放函数参数、局部变量、返回值等,操作方式类似于数据结构的栈。
堆区:程序员可动态操作的内存区,操作方式类似于链表。
全局/静态区:保存全局变量和static变量,程序运行结束时由系统释放。
常量区:存放常量。
代码区:存放二进制代码。

14、malloc函数和new的区别
均是用于申请动态内存。
malloc是库函数,用户需要指定需要的内存大小。
new是C++关键字,用户无需指定需要的内存大小。
C++添加new的原因:malloc不能满足动态对象,因为对象在创建时会自动调用构造函数,对象销毁之前又会调用析构函数。malloc是库函数,不在编译器控制权限之内,不能够把执行构造函数和析构函数的工作强加给malloc去完成,而new会调用对象的构造函数实现对象的初始化。
保留malloc的原因:C++代码中经常会调用c函数,而c代码没有new,只能用malloc。
new/delete、malloc/free必须成对使用。

15、delete []a和delete b的区别
前者是释放多个同一类型的地址空间,后者是释放一个某种类型的地址空间。可以理解a是指针数组,b是一个指针。

16、用宏定义声明1年有多少秒
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

17、头文件中#ifndef、#define、#endif的作用
防止重复定义

18、头文件的作用
1、调用其他函数接口
2、将函数声明和实现分离
3、加强类型安全检查

19、重载overload和重写override的区别
重载:同一个类中,函数名相同,但是参数不同的成员函数。
重写:派生类重写基类的函数,函数名和参数均相同,但是基类函数必须有virtual关键字。
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时,基类的函数被隐藏。
(3)任何条件下都要禁止重新定义继承而来的非虚函数。

20、封装、继承与多态
封装:将数据或函数等集成到类中,能够保护或者防止代码(数据)被破坏。
继承:实现了代码或接口的重复使用,节省重复开发时间,子类可以继承父类的一些方法。
多态:根据调用方法的对象,相同的方法可作用于多种类型的对象上并获得不同的结果。

21、虚函数、纯虚函数
虚函数:在调用不同的衍生类的同名函数时,可以调用类实例调用正确的函数。虚函数实现了多态。
纯虚函数:为了满足许多情况下基类不能对虚函数给出有意义的实现,只是给出一个虚函数声明。示例:virtual int func(int n) const =0; 包含纯虚函数的类是抽象基类,抽象基类不能创建对象,但可以声明指向抽象基类的指针或引用。

22、继承(Inheritance)、关联(Association)、聚合(Aggregation)以及组合(Composition)的区别
继承:子类继承父类的方法,并可以增加自己的功能。可以用"Is a"表示,如a dog is a animal。
关联:类之间的弱联系,在C++中表现为一个类作为另一个类方法的参数。如class A;class B;A::Function1(B &b);
聚合:整体和部分的关系。从别的类中获取函数来组成一个新类,或在新类中添加其他代码的一个常用的接口。可以用"has a"表示,如A dog has a name。
组合:整体和部分的关系,只是整体和部分具有统一的生命周期。可以理解为一个类中内嵌其他类的对象作为自己的成员。

23、C++智能指针
在c++ 中没有垃圾回收机制,又极高频率的使用了指针。为了实现指针指向内存的安全回收,对指针进行了一层封装,即智能指针。
常见的智能指针:auto_ptr ,  unique_ptr , shared_ptr 。

24、字符串常用函数的实现,如strcpy
1、atoi实现(字符串转换为整数)
2、itoa实现(整数转换为字符串)
3、strcmp实现(比较两个字符串大小)
4、strcpy实现(拷贝字符串到指定位置)
5、strlen实现(字符串长度)
6、strstr实现(寻找子串出现的位置)
7、memcpy实现(内存级的复制内容)
8、memmove实现(内存级的复制)
9、reverse实现(反转一个字符串)
10、reverse_sentence(反转一句话中的每一个单词)
 

猜你喜欢

转载自blog.csdn.net/u011376563/article/details/82872369