C/C++笔试题

  很多公司面试的题目都是一些比较常见和实用的题目,但是往往我们由于面试时间等等原因回答的不够全面和不够满意,所以我们在看面试题的时候要当成知识点来学习,而不是记住用来面试,下面分享总结一下一些常见的面试题目,希望对大家有帮助。

一、const的作用
定义:const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。

内存:C语言存储在堆栈和静态存储区(全局变量),C++可能存在符号表中,视情况而定。

读写属性:只读

主要作用:
1)可以定义const常量,具有不可变性。
2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。
3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!
4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
5)可以节省空间,避免不必要的内存分配。const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。
6)提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。(C++)。

意义:const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

典型例子:
1.修饰局部变量
  const int n=5;
  int const n=5;
两种写法效果一样,都是不能再次赋值了。

2.修饰常量静态字符串
const char* str="abcdef";
如果没有const的修饰,我们可能会在后面有意无意的写str[4]=’x’这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了const,这个错误就能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译期被发现

3.修饰指针,常量指针和指针常量
常量指针写法:const int * n;int const * n;两个都是表示常量指针
常量指针指的是不能通过这个指针来改变变量的值,但是可以通过引用和指向其他地址来改变值。
int a=5;const int* n=&a;a=6;//通过引用来改变常量指针的值
int a=5;int b=6;const int* n=&a;n=&b;//通过指向地址来改变常量指针的值

指针常量的写法:int *const n;
指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的

指向常量的常指针:const int* const p;
是以上两种的结合,指针指向的位置不能改变并且也不能通过这个指针改变变量的值,但是依然可以通过其他的普通指针改变变量的值。


4.修饰函数的参数
根据常量指针与指针常量,const修饰函数的参数也是分为三种情况

1)防止修改指针指向的内容 void StringCopy(char *strDestination, const char *strSource);
其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图改动 strSource 的内容,编译器将指出错误。

2)防止修改指针指向的地址 void swap ( int * const p1 , int * const p2 )
指针p1和指针p2指向的地址都不能修改。

3)以上两种的结合。

5.修饰函数的返回值
如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
例如定义函数:const char * GetString(void);
char *str = GetString();//出现编译错误
const char *str = GetString();//正确

6.修饰函数和对象(C++):int fun()const;
1)const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。
2)如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数
3)const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。
4)类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符


二、关键字static的作用
定义:static修饰为静态,可以修饰变量,函数。。
内存:静态存储区

读写属性:可读可写

意义:静态,重在静也是禁止,限制的意思,禁止被外部使用,禁止每次都初始化。

主要作用:
1、修饰全局变量:静态全局变量
1)静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突;
2)和全局变量的区别:
  全局变量是不显式用static修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。
  全局静态变量是显式用static修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用extern声明也不能使用。

2、修饰局部变量:静态局部变量
1)该变量在全局数据区分配内存;
2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;(重点)
3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

3、修饰函数:在函数的返回类型前加上static关键字,函数即被定义为静态函数
1)静态函数不能被其它文件所用;其它文件中可以定义相同名字的函数,不会发生冲突;

4.类成员的静态修饰

4.1静态数据成员:在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员
1)对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;

2)静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。,语句int Myclass::Sum=0;是定义静态数据成员;class Myclass{static int Sum;//声明静态数据成员}

3)因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有

产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它。

4.2静态成员函数
1)出现在类体外的函数定义不能指定关键字static;class Myclass{static void GetSum(); // 声明静态成员函数};;;
void Myclass::GetSum() //静态成员函数的实现 //类外
{
    // cout<<a<<endl; //错误代码,a是非静态数据成员
    cout<<"Sum="<<Sum<<endl;
}

2)静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

3)非静态成员函数可以任意地访问静态成员函数和静态数据成员;

4)静态成员函数不能访问非静态成员函数和非静态数据成员;


三、指针和引用的区别
1.引用是别量的一个别名,指针是个实体,他在栈中有自己的使用空间(内存方面的)
2.引用必须初始化和赋值,其他时候不能被改变,指针可以不初始化,指针的值可以在任何时候被改变
3.“sizeof 引用" = 指向变量的大小 , "sizeof 指针"= 指针本身的大小
4.指针和地址运用自增(++)不同,引用是值进行自增,而指针是地址进行自增;
5.引用使用在源代码级相当于普通的变量一样使用,做函数参数时,内部传递的实际是变量地址
6.指针有多级指针,引用没有。

四. C++中有了malloc / free , 为什么还需要 new / delete     
  1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
  2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
  3,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

五、堆和栈的区别
1.栈区:由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2.堆区:一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。
3.申请方式和回收方式不同。(看上)
4.申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆。
5.申请效率的比较(栈快)
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
6.申请大小的限制。(堆大)
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。容量由系统预选预定好,window(2M)
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。容量由计算机中的虚拟内存决定。
7.存取效率的比较(栈快)


六.在c++程序中调用被C编译器编译后的函数,为什么要加extern“C”
1.extern"c‘’是c++编译器提供的与c连接交换指定的符号,用来解决名字匹配问题。
  C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同,
假设某个函数原型为:void foo(int x, inty);
该函数被C编译器编译后在库中的名字为:  _foo
而C++编译器则会产生像: _foo_int_int   之类的名字


七.头文件种的ifndef/define/endif 是干什么用的
1.防止头文件被重复包含和定义。


八.进程间的通信方式
管道、有名管道、信号、共享内存、消息队列、信号量、套接字、文件.



九.什么时候要用虚析构函数
1.过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而导致内存泄漏
  在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。



十.什么是封装继承和多态
1.封装:
封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。
封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

2.继承:
继承主要实现重用代码,节省开发时间。子类可以继承父类的一些东西。

3.多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。


十一.什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误?
1.用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露。
2.使用的时候要记得指针的长度.
3.申请内存的时候确定在哪里释放
4.对指针赋值的时候应该注意被赋值指针需要不需要释放.
5.动态分配内存的指针最好不要再次赋值.

十二.请用简单的语言告诉我C++ 是什么?
  C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛。C++支持多种编程范式 --面向对象编程、泛型编程和过程化编程。 其编程领域众广,常用于系统开发,引擎开发等应用领域,是最受广大程序员受用的最强大编程语言之一,支持类:类、封装、重载等特性!


十三.C和C++的区别?
  c++在c的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。



十四.结构体和联合体的区别
1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。

2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。



十五.#i nclude<file.h> 与 #i nclude "file.h"的区别?
  前者是从编译器从标准库目录开始寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。


十六.重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
  重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
  重写:是指子类重新定义复类虚函数的方法。
原因:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!

重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。


十七.main 函数执行以前,还会执行什么代码?
1.全局对象的构造函数会在main 函数之前执行,全局对象的析构函数会在main函数之后执行;用atexit注册的函数也会在main之后执行.
2.一些全局变量、对象和静态变量、对象的空间分配和赋初值就是在执行main函数之前,而main函数执行完后,还要去执行一些诸如释放空间、释放资源使用权等操作
3.进程启动后,要执行一些初始化代码(如设置环境变量等),然后跳转到main执行。


十八.struct 和 class 的区别
  struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。


十九.请说出const与#define 相比,有何优点?
1. const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2.有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。



二十.如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif



二十一.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
c用宏定义,c++用inline


二十二.SendMessage和PostMessage有什么区别
  SendMessage是阻塞的,等消息被处理后,代码才能走到SendMessage的下一行。PostMessage是非阻塞的,不管消息是否已被处理,代码马上走到PostMessage的下一行。


二十三.strcpy()和memcpy()的区别?
  strcpy()和memcpy()都可以用来拷贝字符串,strcpy()拷贝以’\0’结束,但memcpy()必须指定拷贝的长度。


二十四.什么是指针?谈谈你对指针的理解?
1.指针是一个变量,该变量专门存放内存地址;
2.指针变量的类型取决于其指向的数据类型,在所指数据类型前加*
3.指针变量的特点是它可以访问所指向的内存。


二十五. assert()的作用?
  ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。


二十六.系统会自动打开和关闭的3个标准的文件是?
1.标准输入—-键盘—stdin
2.标准输出—-显示器—stdout
3.标准出错输出—-显示器—stderr


二十七.数组在做函数实参的时候会转变为什么类型?
  数组在做实参时会变成指针类型。


二十八.关键字volatile有什么含意? 并给出三个不同的例子。
  一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存里的备份。下面是volatile变量的几个例子:
1.并行设备的硬件寄存器(如:状态寄存器)
2.一个中断服务子程序中会访问到的非自动变量
3.多线程应用中被几个任务共享的变量

































  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值