如何判断程序是C程序还是CPP程序

1、

根据宏__cplusplus

#include <iostream>
using namespace std;

void main()
{
#ifdef __cplusplus
	cout << "c++" << endl;
#else
	cout << endl;
#endif
	system("pause");
}

2、C++和C的不同

  • 结构体&类,智能指针等等
  • 从机制上:C是面向过程的[可以编写面向对象的程序];C++是面向对象的,提供了类。但是C++编写面向对象的程序比C容
  • 从适用方向:C适合要求代码体积小,效率高的场合,比如嵌入式;C++适合更上层的,复杂的;Linux核心大部分是C写的,因为它是系统软件,效率要求极高
  • C++是C的超级,在C上面扩充而来的
  • C是结构化编程语言,C++是面向对象编程语言
  • C++侧重于对象而不是过程,侧重于类的设计而不是逻辑的设计

3、引用和指针的区别:

  • 指针是通过某个指针变量指向一个对象之后,对它所指向的变量间接操作。程序中使用指针,可读性差;
  • 而引用本身就是模板变量的别名,对引用的操作就是对目标变量的操作。
  • 引用在创建的同时必须初始化,指针可以在任何时候被初始化
  • 引用初始化以后不能被改变,指针可以随时改变所指的对象
  • 不存在指向空值的引用,但是存在指向空值的指针,引用必须与合法的存储单元相关联

4、int id[sizeof(int)];

  • 正确,这个sizeof是编译时运算符,编译时就确定了,可以看成是和机器有关的常量。

const int a = 5;    int b[a];

  • 正确,a不可以改变,直接从表中读取

int c = 5; const int a = a;    int b[a];

  • 不正确,编译器优化

5、静态全局变量的作用域是本文件内部。static int a;

  • 普通全局变量是在函数外部定义的变量,在本文件内部,从定义开始的函数都可以使用它,如果在其他文件中加一个extern就可以引用这个普通全局变量了。如果在普通全局变量中加一个static,就限制它的作用域为本文件内部函数公用,其他文件不可以加extern然后引用它

6、C++函数中值的传递方式有几种?

  • 引用传递[原本]
  • 指针传递[原本]
  • 值传递[副本机制]

7、对于一个频繁使用的短小函数,在C语言中应用宏定义实现,在c++中用inline函数实现。

8、C++中的virtual和inline的含义分别是什么?

  • 在基类成员函数的声明前加上virtual关键字,意味着将该成员函数声明为虚函数。如果派生类能够重新定义基类的方法,则在基类中将该方法定义为虚方法,这样可以启用动态联编。
  • inline与函数的定义放在一起,使该函数称为内联。inline是一种用于实现的关键字,而不是用于声明的关键字。使用内联函数的目的是为了提高函数的运行效率。内联函数体的代码不能过长,因为内联函数省去了调用函数的时间是以代码膨胀为代价的。内联函数不能包含循环语句,因为执行循环语句要比调用函数的开销大
  • virtuel:虚继承,虚函数

9、VC中,编译工具条内的debug和release选项是什么含义

  • debug通常称为调试版本,包含调试信息,并且不做任何优化,便于调试程序。
  • release称为发布版本,往往进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用。
  • debug带有大量的调试代码,运行时需要相应的运行库,release模式紧凑不含有调试代码和信息,直接可以运行[如果不需要运行库]

10、函数assert用法

  • 断言assert是仅在debug版本起作用的宏,用于检查“不应该发生的情况”。可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。

11、const和#define比较,const有什么优点

  • const常量带有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意想不到的错误[边际效应]
  • 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

12、有了malloc/free为什么还有new/delete

  • malloc/free是标准库函数,new/delete是C++的运算符,不是库函数
  • 都可以用于申请动态内存和释放内存
  • 对于非内部数据类型的对象而言,malloc/free无法满足动态对象要求:对象创建的同时要自动执行构造函数,对象销毁之前要执行析构函数。由于malloc/free是库函数不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的new,以及一个清理与释放内存工作的delete。
  • 由于C++中常常调用C程序,因此malloc/free不能被淘汰

13、如果在申请动态内存时找不到足够大的内存块,malloc和new将返回null指针,宣告内存申请失败。你是怎么处理内存耗尽的

  • 判断指针释放为null,如果是就马上用return终止本函数或者用exit(1)终止整个程序
  • 为new和malloc设置异常处理函数。比如VC++中可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc和new共享相同的异常处理程序

14、c++是不是类型安全语言。

  • 不是,用reinterpret_cast可以强制转换两个不同类型的指针。

15、用C++写个程序,判断一个OS是16为的还是32位还是64位。

  • 系统是多少位,就是系统地址总线的条数,等价于系统能够处理的最大位数。而与地址相关的就是指针了,因此:sizeof(指针),如果结果是2,16位;4,32位;8,64位
void main()
{
	cout << sizeof(string *) << endl;

	system("pause");
}

16、多态类中的虚函数表是编译时建立还是运行时建立

  • 虚函数表时在编译时就建立了,各个虚函数这时被组织成立一个虚拟函数的入口地址的数组
  • 而对象的隐藏成员成员---->虚拟函数表指针是在运行期---也就是构造函数被调用时进行初始化的,这就是实现多态的关键。

17、转移字符的判断

  • ‘65’是错误的,因为单引号里面只能是1个字符。
  • ‘\081’中的0表示是8进制,而8进制里面不能有8,error

18、如果数组名作为实参而指针变量作为形参,函数调用实参传递给形参的是:数组第一个元素的地址

void func(int *arr)
{
	cout << arr << endl;  //打印出第一个元素的地址
}

void main()
{
	int a[10] = { 1, 2, 3, 5, 4 };
	func(a);   
	system("pause");
}

19、变量的指针含义是变量的地址

20、内存的分配方式有几种?

  • 从静态存储区域分配:内存在程序编译时候就已经分配好,这块内存在程序的整个运行期间都存在。比如全局变量
  • 在栈上创建:在执行函数时,函数内部的局部变量和形参都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  • 从堆上分配:也叫做动态内存分配,手动申请手动释放。

21、float a, b, c,问等式(a+b)+c == (b+a)+c,和(a+b)+c == (a+c)+b是否成立

  • 两种都不行。在比较float和double时,不能简单的比较,由于计算误差。相等的概率很低。应该判断两数之差是否落在区间[-e,e]之内。这个e应该比浮点数的精度大1个数量级。

22、全局变量和局部变量有什么区别?是怎么实现的?OS和编译器是怎么知道的?

  • 声明周期不同:全局变量随主程序创建和销毁;局部变量在局部函数/局部循环体等内部存在,退出就不存在
  • 使用方式不同:通过声明后程序的各个部分都可以用到;局部变量只能在局部使用,分配在栈区
  • OS和编译器通过内存分配的位置来知道的,全局变量分配在全局数据端并且在程序开始运行时被加载。局部变量分配在堆栈里面。

23、heap和stack的差别

(1)堆栈空间分配区别

  • 栈:操作系统自动分配和释放,存放函数的参数,局部变量等,类似于数据结构中的栈
  • 堆:手动管理手动释放,如果不释放,可能会内存泄漏。等到程序完成之后,OS回收
  • 栈空间有限,堆是很大的自由存储区

(2)堆栈缓存方式区别

  • 栈使用的是一级缓存,被调用时处于存储空间,调用完毕立即释放
  • 堆存放在二级缓存,声明周期由虚拟机的垃圾回收算法决定。因此速度慢一些

(2)数据结构的堆和栈:

  • 堆:树
  • 栈:先进后出的数据结构

24、explicit和protected是什么意思

(1)explicit

  • 修改类的构造函数,不允许发生隐式转换
#include <iostream>
using namespace std;

class String {
public:
	explicit String(int n) {};
	String(const char *p) {};
};

void main()
{
	String s1(11);    //只能写成这种形式,不能用=强制转换
	//String s2 = 11;  //error,必须显示的调用,
	system("pause");
}

(2)protected

25、重复多次fclose一个打开过一次的FILE *fp指针会有什么结果,并请解释。

  • 导致文件描述符结构中指针指向的内存被重复释放,进而导致一些不可预期的异常。

26、为什么数组名作为参数,会改变数组的内容,而其他类型如int却不会改变变量的值

  • 当数组名作为参数时,传递的实际上是地址。而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调用函数内部对形参的改变并不影响实参的值
  • C中只有数组没有副本机制

27、如果不使用常量,直接在程序中填写数字或者字符串,将会有什么麻烦

  • 可读性变差,不记得为什么要用这个数字./字符串
  • 可能会书写错误
  • 难修改

28、为什么要使用堆

  • new是为了申请堆内存
  • heap比stack的优势在于容量巨大,一般一个程序只有2M左右[取决于编译器]
  • heap需要手动释放内存,但是随时可以释放,使用stack必须等到声明周期结束后才会释放。
  • 对于声明周期短而且占用空间小的如局部变量用stack,占用空间大的用heap

29、const关键字由哪些作用

  • 想要阻止一个变量被改变,用const:const int a = 5。定义的同时必须初始化,因此以后就不能改变它了
  • 指针:指针本身为const,指针所指向对象位const,二者同时位const
  • 在一个函数声明中,const修饰形参,表示它是一个输入参数,在函数内部不能改变其值。
  • 对于类的成员函数,如果指定其为const,则表明是一个常函数,不能修改类的成员变量
  • 对于类的成员函数,指定返回值为const,表示其返回值不为“左值”

30、是不是父类写了一个virtual函数,如果子类覆盖它的函数不加virtual,也能实现动态

  • virtual修饰符会被隐形继承的。virtual可以加也可以不加
  • 子类的空间里有父类的所有变量[static除外]。也就是说,子类空间里含有父类的私有变量。私有变量不能直接访问
  • 同一个函数只存在一个实体[inline除外]??
  • 子类覆盖它的函数不加virtual,也能实现多态。

31、面向对象的3个基本特征

(1)封装:就是对数据进行权限控制

  • 将客观事物抽象成类,每个类对自身的数据和方法实行private,protected、public

(2)继承:[代码重用]

  • 实现继承:指使用基类的属性和方法而无须额外编码的能力
  • 可视继承:子窗体使用父窗体的外观和实现代码
  • 接口继承:仅仅使用属性和方法,实现滞后到子类实现。
  • 前两者[类继承]和后一种[对象组合-->接口继承以及纯虚函数]构成了代码复用的两种方式。

(3)多态[一个接口多个操作]

  • 是将父对象设置成为和一个或者更多的与它的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。即允许将子类类型的指针赋值给父类类型的指针。

42、重载、重写、重定义的区别

43、多态的作用

  • 隐藏实现细节,使得代码能够模块化
  • 扩展代码模块,实现代码复用
  • 接口重用:为了类在继承和派生的时候,保证使用家族中任一类型的实例的某一属性时的正确调用

44、当一个类A中没有声明任何成员变量与成员函数,这是sizeof(A)?,如果不是0,编译器为什么没有让它为0

  • 1。
  • 类的实例化就是在内存中分配一块地址。每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器会给一个空类隐含的加一个字节,这样空类在实例话后再内存得到了独一无二的地址

猜你喜欢

转载自blog.csdn.net/zhizhengguan/article/details/81414481