C++面试题,阿里、百度、腾讯、华为、小米100道C++面试题目及答案

2022-12-02 14:47:01 浏览数 (1)

一、【阿里C 面试题】

1、如何初始化一个指针数组。

答案: c 中的指针是一个很经典的用法,但是也是最容易出错的,比如定义了一个指针,必须对其进行初始化,不然这个指针指向的是一个未知的内存地址,后续对其操作的时候,会报错。这只是其次,最让人头疼的就是指针错误问题,往往编译的时候可以通过,在程序运行的时候,就会出现异常,如果对程序不是很熟悉,则不是很容易找到问题所在,我最近就遇到过很多这样的问题,定义了一个结构体指针,使用的时候忘记初始化,导致在后边使用的时候程序报异常。下面就总结一下c 指针初始化的一些方法,

以及我自己遇到的一些问题以及心得体会。

一.c 指针初始化的一般方法:

1.将一个已经在内存中存在变量的地址传递给定义的指针,这个指针就指向这个变量的内存地址(相同的数据类型),完成初始化。

比如:

代码语言:javascript复制
int a=2;
int *b=&a;

2.利用new开辟一块地址空间

代码语言:javascript复制
struct test{
       int a;
       int b;
}*t;
 
void main()
{
    int c=0;
    test *t=new test();
    c=t->a;
}

使用 new开辟的空间,记得使用delete释放,因为new出来的是返回的堆的空间,堆的空间是不会自动释放的,存放变量的栈才会自动释放。delete释放其实只是释放了申请的这块内存空间,但是指针并没有没撤销,指针还是指向这块地址,但是不可用(靠人品吃饭的有可能可以用),是非法的。所以用delete释放掉一块堆内存时,应该自己手动将指针设置为NULL。

3.把指针设置为NULL或者0 这样做一般只是为了没有具体初始化的时候做的,这样避免了野指针,后面可以使用if(指针==NULL)来判断,然后再进行操作。

错题解析:首先明确一个概念,就是指向数组的指针,和存放指针的数组。 指向数组的指针:char (*array)[5];含义是一个指向存放5个字符的数组的指针。 存放指针的数组:char *array[5];含义是一个数组中存放了5个指向字符型数据的指针。 按照题意,我理解为初始化一个存放指针的数组,char *array[2]={“China”,”Beijing”};其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串”China”和”Beijing”。

2、关键字const是什么含意?

正确答案: 在标准C 中,这样定义的是一个常量,用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。

const使用(类型): 1、用于指针的两种情况:const是一个左结合的类型修饰符. int const*A;//A可变,A不可变 intconst A;//A不可变,*A可变

2、限定函数的传递值参数: void function(const int Var);//传递过来的参数在函数内不可以改变.

3、限定函数返回值型. const int function();//此时const无意义 const myclassname function();//函数返回自定义类型myclassname.

4、限定函数类型. void function()const;//常成员函数,常成员函数是不能改变成员变量值的函数。

错题解析:我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可 以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如果应试者能正确回答这 个问题,我将问他一个附加的问题:下面的声明都是什么意思? const int a; int const a; const int *a; int * const a; int const * a const; 前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整 型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型 数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由: 1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理 其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。) 2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。 3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

3、 什么是动态特性?

正确答案: 在绝大多数情况下,程序的功能是在编译的时候就确定下来的,我们称为静态特性。反之,如果程序的功能是在运行时刻才确定下来的,则称为动态特性。

动态特性是面向对象语言最强大的功能之一,因为它在语言层面上支持程序的可扩展性,而可扩展性是软件设计追求的重要目标之一。

c 虚函数、抽象基类、动态绑定、多态构成了出色的动态特性。

1.虚函数

假定几何形状的基类为Shape,其派生类有Circle、Rectangle、Ellipse等,每个派生类都能够绘制自己所代表的形状。不管派生类的形状如何,我们希望用统一的方式来调用绘制函数,最好是使用Shape定义的接口函数Draw(),并让程序在运行是动态地确定应该使用哪一个派生类的Draw()函数。

为了使这种行为可行,我们把基类Shape中的函数Draw()声明为虚函数,然后在派生类中重新定义Draw()使之绘制正确的形状,这种方法叫覆盖,虚函数的声明方法是在基类的函数原型之前加上关键之virtual。

一旦类的一个函数被声明为虚函数,那么其派生类的对应函数也自动成为虚函数,这样一级一级传递下去。

2.抽象基类

当我们把类看成是一种数据类型时,通常会认为该类肯定是要被实例为一个或多个对象的。但是在很多情况下,定义那些不能实例化出对象的类也是很有用的,这种类就称为抽象类。抽象类的唯一目的就是让其派生类继承并实现它的接口方法,因此它通常也被称为抽象基类。

如果将基类的虚函数声明为春虚函数,那么该类就被定义为了抽象基类。純虚函数是在声明时将其“初始化”为0的函数,例如:

代码语言:javascript复制
  class Shape {     //Shape是抽象基类
  public:
 		 virtual void Draw(void)=0;  //Draw()为純虚函数
   }

`抽象基类Shape的純虚函数Draw()根本不知道自己应该怎么绘制出一个“形状”来,具体功能必须有代表具体形状的派生类对应的Draw()函数来实现。 我们知道,函数名就是函数的地址,将一个函数初始化为0意味着函数的地址将为0,这就是在告诉编译器,不要为该函数编址,从而阻止该类的实例化行为。 抽象基类的主要用途是“接口与实现分离”;不仅要把数据成员(信息)隐藏起来,而且还要把实现完全隐藏起来,只留一些接口给外部调用。

代码语言:javascript复制

错题解析:在绝大多数情况下, 程序的功能是在编译的时候就确定下来的, 我们称之为静态特性。 反之, 如果程序的功能是在运行时刻才能确定下来的, 则称之为动态特性。C 中, 虚函数,抽象基类, 动态绑定和多态构成了出色的动态特性。

4、基类的有1个虚函数,子类还需要申明为virtual吗?为什么。

正确答案:建议加上vitrual,代码是写给人看的 错题解析:不申明没有关系的。 不过,我总是喜欢显式申明,使得代码更加清晰。

5、在C 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?

正确答案: c语言程序和c 程序在编译时,是相互独立的编译;在.c文件中,编译器将Add函数重命名为_Add; 而在.cpp文件中,编译器将用extern声明的函数重命名为(?Add@@YAHHH@Z);那么在链接阶段,在_mian函数中该Add函数被调用; 此时编译器带着(?Add@@YAHHH@Z)函数名进入test.c文件的编译文件中去寻找(?Add@@YAHHH@Z)函数,但是在test.c文件中这个Add函数被编译器重命名为_Add,由于在.cpp文件中和.c文件中同一个函数名被编译器重命名后的名字不一样;所以.cpp文件声明的外部函数找不到真正定义的地方;程序错误; (2)使用extern “C” int Add(int,int); 外部函数—-正确

代码语言:javascript复制
#include<iostream>
using namespace std;
extern "C" int Add(int,int);
int main()
{
    cout<<Add(50,50)<<endl;
    return 0;
}

解释: c 语言为了支持重载,对编译时函数的重命名规则进行更改, 使用extern “C” 的方式在c 程序中声明c语言文件中的函数,可以在编译时,告诉编译器使用C语言的规则对该函数的的函数名的进行重命名,这样在链接的时候,就可以顺利在.c文件中找到该函数; 错题解析:函数和变量被C 编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C 程序不能直接调用C 函数。C 提供了一个C 连接交换指定符号extern“C”来解决这个问题。

6、如何定义Bool变量的TRUE和FALSE的值。

正确答案: 对于C语言,并不存在系统自带的bool类型和False和Ture的定义,如果要使用则必须自定义类型。

有两种常见的方法。 1、使用宏定义。 通过define来进行定义False和True。可以采用如下方式: (1) 直接定义数值

代码语言:javascript复制
#define False 0
#define True 1

(2) 通过逻辑判断定义

代码语言:javascript复制
#define False (1!=1)
#define True (1==1)

2、使用枚举定义。 这种方法可以同时定义类型BOOL

代码语言:javascript复制
typedef enum
{
    False,
    True
}BOOL;

错题解析:不知道这个题有什么陷阱,写到现在神经已经大了,一般来说先要把TURE和FALSE给定义了,使用#define就可以: #define TURE 1 #define FALSE 0 如果有一个变量需要定义成bool型的,举个例子:bool a=TURE;就可以了。

7、内联函数INline和宏定义一起使用的区别。

正确答案: 1、宏定义不会进行类型的判断,只是单存的替换文本; inline会对参数类型进行判断。 2、宏不是函数,inline修饰的是函数。 3、宏返回值不能强制转换成合适的类型,inline返回值可以。

错题解析:内联函数是在编译的时候已经做好将对应的函数代码替换嵌入到对应的位置,适用于代码较少的函数。 宏定义是简单的替换变量,如果定义的是有参数的函数形式,参数不做类型校验。

8、编写my_strcpy函数,实现与库函数strcpy类似的功能,不能使用任何库函数;

正确答案: char *strcpy(char *strDest, const char *strSrc) { if ( strDest == NULL || strSrc == NULL) return NULL ; if ( strDest == strSrc) returnstrDest ; char *tempptr = strDest ; while( (*strDest = *strSrc ) != ‘’); returntempptr ; }

9、 完成程序,实现对数组的降序排序

#include void sort(int array[] ); int main() { int array[]={45,56,76,234,1,34,23,2,3}; //数字任//意给出 sort( array ); return 0; } void sort( int array[] ) {____________________________________ inti,j,k; for(i=1;i<=7;i ) { if(array[i]>array[i-1]) { k=ARRAY[i]; j=i-1; do { array[j 1]=array[j]; j– ; } while(k>array[j]&&j>=0); array[j 1]=k; } } —————————————————– }

10、ICMP是什么协议,处于哪一层?

正确答案: Internet控制报文协议,处于网络层(IP层)

11、 C中static有什么作用

正确答案: (1)隐藏。 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。 (2)static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量。 (3)static的第三个作用是默认初始化为0.其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0×00,某些时候这一特点可以减少程序员的工作量。

12、 Void GetMemory2(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, “hello”); printf(str); } 请问运行Test函数会有什么样的结果?

正确答案: 可以运行

13、C 特点是什么,如何实现多态?画出基类和子类在内存中的相互关系。

正确答案: 多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。 子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,operator=函数,友元函数等等

14、 C 中的什么是多态性? 是如何实现的?

正确答案: 多态性是面向对象程序设计语言继数据抽象和继承之后的第三个基本特征。它是在运行时出现的多态性通过派生类和虚函数实现。基类和派生类中使用同样的函数名, 完成不同的操作具体实现相隔离的另一类接口,即把" w h a t"从"h o w"分离开来。多态性提高了代码的组织性和可读性,虚函数则根据类型的不同来进行不同的隔离。

15、 关键字static的作用是什么?

正确答案: 这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用: 1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。 大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数 据和代码范围的好处和重要性。

16、#define MAX_LEN 500 char arry[MAX_LEN]; cin>>arry; 这段代码有问题吗?若有,请指出并修改;

正确答案: 有问题。头文件缺少。 #include

17、delete []arry 和 delete arry 一样吗?不一样请说明;

正确答案: delete []arry 释放的是多个同一类型的地址空间 Delete[]arry 释放的是一个某种类型的地址空间

18、 多态的作用?

正确答案: 主要是两个: 1)隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用; 2)接口重用,为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

19、C语言的volatile的含义是什么。使用时会对编译器有什么暗示。

正确答案: 从词面上讲,volatile的意思是易变的,也就是说,在程序运行过程中,有一些变量可能会被莫名其妙的改变,而优化器为了节约时间,有时候不会重读这个变量的真实值,而是去读在寄存器的备份,这样的话,这个变量的真实值反而被优化器给“优化”掉了,用时髦的词说就是被“和谐”了。如果使用了这个修饰词,就是通知编译器别犯懒,老老实实去重新读一遍!可能我说的太“通俗”了,那么我引用一下“大师”的标准解释: volatile的本意是“易变的” 。 由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。 下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

20、 请简述以下两个for循环的优缺点

1)for (i=0; i<n; i ) { if (condition) DoSomething(); else DoOtherthing(); } 2)if (condition) { for (i=0; i<n; i ) DoSomething(); } else { for (i=0; i<n; i )=“” dootherthing();=“” }=“”

正确答案: 1)优点:程序简洁。=“” 缺点:多执行了n-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。=“” 2)优点:循环的效率高。缺点:程序不简洁。="

二、【百度C 面试题】

1、 预处理器标识#error的目的是什么?

正确答案: 如果你不知道答案,请看参考文献1。

2、C语言的volatile的含义是什么。使用时会对编译器有什么暗示。

正确答案: 从词面上讲,volatile的意思是易变的,也就是说,在程序运行过程中,有一些变量可能会被莫名其妙的改变,而优化器为了节约时间,有时候不会重读这个变量的真实值,而是去读在寄存器的备份,这样的话,这个变量的真实值反而被优化器给“优化”掉了,用时髦的词说就是被“和谐”了。如果使用了这个修饰词,就是通知编译器别犯懒,老老实实去重新读一遍!可能我说的太“通俗”了,那么我引用一下“大师”的标准解释: volatile的本意是“易变的” 。 由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。 下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

3、 MFC中CString是类型安全类么?

正确答案: 不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换

4、内联函数INline和宏定义一起使用的区别。

正确答案: 内联函数是在编译的时候已经做好将对应的函数代码替换嵌入到对应的位置,适用于代码较少的函数。 宏定义是简单的替换变量,如果定义的是有参数的函数形式,参数不做类型校验。

5、C 中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中?

正确答案: 栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理 堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上

6、DB事务处理的四个特性:

正确答案: 原子性,一致性,隔离性,持久性 就答对一个:一致性,

7、如何初始化一个指针数组。

正确答案: 首先明确一个概念,就是指向数组的指针,和存放指针的数组。 指向数组的指针:char (*array)[5];含义是一个指向存放5个字符的数组的指针。 存放指针的数组:char *array[5];含义是一个数组中存放了5个指向字符型数据的指针。 按照题意,我理解为初始化一个存放指针的数组,char *array[2]={“China”,”Beijing”};其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串”China”和”Beijing”。

8、 int i=(j=4,k=8,l=16,m=32); printf(“%d”, i); 输出是多少?

正确答案: 相当于 i=j=4;i=k=8;i=l=16;i=m=32; 故最后i=32;

9、如何在C中初始化一个字符数组。

正确答案: 这个问题看似很简单,但是我们要将最简单的问题用最严谨的态度来对待。关键的地方:初始化、字符型、数组。最简单的方法是char array[];。这个问题看似解决了,但是在初始化上好像还欠缺点什么,个人认为:char array[5]={’1′,’2′,’3′,’4′,’5′};或者char array[5]={“12345″};或者char array[2][10]={“China”,”Beijing”};也许更符合“初始化”的意思。

10、参数传递有几种方式;实现多态参数传递采用什么方式,如果没有使用某种方式原因是什么;

正确答案: 传值,传指针或者引用

11、请填写BOOL , float, 指针变量 与“零值”比较的 if 语句。

正确答案: 这里“零值”可以是0, 0.0 , FALSE或者“空指针”。例如 int 变量 n 与“零值”比较的 if 语句为:

代码语言:javascript复制
if ( n == 0 )
if ( n != 0 )

12、C 特点是什么,如何实现多态?画出基类和子类在内存中的相互关系。

正确答案: 多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。 子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,operator=函数,友元函数等等

13、 什么是“引用”?申明和使用“引用”要注意哪些问题?

正确答案: 引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引 用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只 表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。

14、触发器怎么工作的?

正确答案: 触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数据的处理必须符合由这些SQL 语句所定义的规则。

15、C也可以通过精心封装某些函数功能实现重用,那C 的类有什么优点吗,难道仅仅是为实现重用。

正确答案: 并不仅仅是这样的。 OOD,OOP从根本上改变了程序设计模式和设计思想,具备重大和深远的意义。 类的三大最基本的特征:封装,继承,多态.

16、CSingleLock是干什么的。

正确答案: 同步多个线程对一个数据类的同时访问

17、 C 中引用和指针的区别?

正确答案: 引用是对象的别名, 操作引用就是操作这个对象, 必须在创建的同时有效得初始化(引用一个有效的对象, 不可为NULL), 初始化完毕就再也不可改变, 引用具有指针的效率, 又具有变量使用的方便性和直观性, 在语言层面上引用和对象的用法一样, 在二进制层面上引用一般都是通过指针来实现的, 只是编译器帮我们完成了转换。 之所以使用引用是为了用适当的工具做恰如其分的事, 体现了最小特权原则。

18、 C与C 各自是如何定义常量的?有什么不同?

正确答案: C中是使用宏#define定义, C 使用更好的const来定义。 区别: 1)const是有数据类型的常量,而宏常量没有,编译器可以对前者进行静态类型安全检查,对后者仅是字符替换,没有类型安全检查,而且在字符替换时可能会产生意料不到的错误(边际效应)。 2)有些编译器可以对const常量进行调试, 不能对宏调试。

19、 C 函数中值的传递方式有哪几种?

正确答案: C 函数的三种传递方式为:值传递、指针传递和引用传递。

20、一般数据库若出现日志满了,会出现什么情况,是否还能使用?

正确答案: 只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记录日志。也就是说基本上处于不能使用的状态。

三、【腾讯C 面试题】

1、.C 里面如何声明constvoidf(void)函数为C程序中的库函数?

正确答案: 在该函数前添加extern “C”声明。由于编译后的名字不同,C 程序不能直接调用C 函数。

2、c 中类和c语言中struct的区别(至少两点)

正确答案: (1)c 中的类默认的成员是私有的,struct默认的是共有的。

(2)c 中的类可以定义成员函数,struct只能定义成员变量。

(3)C 中的类有继承、多态的特性,struct没有。

3、IP组播有那些好处?

正确答案: Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播技术的核心就是针对如何节约网络资源的前提下保证服务质量。

4、变量的声明和定义有什么区别?

正确答案: 声明变量不分配空间,定义变量要分配空间。声明主要是告诉编译器,后面的引用都按声明的格式。定义其实包含了声明的意思,同时要分配内存空间。

5、程序什么时候应该使用线程,什么时候单线程效率高。

正确答案: 1 耗时的操作使用线程,提高应用程序响应

2 并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。

3 多CPU系统中,使用线程提高CPU利用率

4 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

其他情况都使用单线程。

6、介绍一下模板和容器。如何实现?(也许会让你当场举例实现)

正确答案: 模板可以说比较古老了,但是当前的泛型编程实质上就是模板编程。 它体现了一种通用和泛化的思想。 STL有7种主要容器:vector,list,deque,map,multimap,set,multiset.

7、以下为WindowsNT下的32位C 程序,请计算sizeof的值

charstr[]=“Hello”; charp=str; intn=10; //请计算 sizeof(str)=? sizeof§=? sizeof(n)=? voidFunc(charstr[100]) { //请计算 sizeof(str)=? } voidp=malloc(100); //请计算 sizeof§=?

正确答案: sizeof (str ) = 6 sizeof ( p ) = 4 sizeof ( n ) =4 void Func ( char str[100]) { sizeof( str ) = 4 } void *p = malloc( 100 ); sizeof ( p ) =4

8、C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?inta=5,b=7,c;c=a b;

正确答案: 这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成: c = a b; 因此, 这段代码持行后a = 6, b = 7, c = 12。 如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题

9、#include与#include“file.h”的区别?

正确答案: 前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

10、如何在C中初始化一个字符数组。

正确答案: 这个问题看似很简单,但是我们要将最简单的问题用最严谨的态度来对待。关键的地方:初始化、字符型、数组。最简单的方法是char array[];。这个问题看似解决了,但是在初始化上好像还欠缺点什么,个人认为:char array[5]={’1′,’2′,’3′,’4′,’5′};或者char array[5]={“12345″};或者char array[2][10]={“China”,”Beijing”};也许更符合“初始化”的意思。

11、在C 程序中调用被C编译器编译后的函数,为什么要加extern“C”?

正确答案: extern是C/C 语言中表明函数和全局变量作用范围(可见性)的关键字,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。

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

正确答案: 1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。

2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

13、在C 程序中调用被C编译器编译后的函数,为什么要加extern"C"?

正确答案: C 语言支持函数重载,C语言不支持函数重载。函数被C 编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C 编译器则会产生像_foo_int_int之类的名字。C 提供了C连接交换指定符号extern"C"来解决名字匹配问题。

14、如何让局部变量具有全局生命期。

正确答案: 具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

15、解释堆和栈的区别。

正确答案: 具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

16、在C 程序中调用被C编译器编译后的函数,为什么要加extern“C”声明?

正确答案: 函数和变量被C 编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C 程序不能直接调用C 函数。C 提供了一个C 连接交换指定符号extern“C”来解决这个问题。

17、strtok函数在使用上要注意什么问题。

正确答案: 这个问题我不知道能不能回答全面,因为实在是用的很少。这个函数的作用是分割字符串,但是要分割的字符串不能是常量,这是要注意的。比如先定义一个字符串:char array[]=”part1,part2″;,strtok的原形是char *strtok(char *string, char *delim);,我们将”,”作为分隔符,先用pt=strtok(array,”,”);,得到的结果print出来就是”part1″,那后面的呢,要写成pt=strtok(NULL,”,”);,注意,要用NULL,如果被分割的字符串会被分成N段,那从第二次开始就一直要用NULL。总结起来,需要注意的是:被分割的字符串和分隔符都要使用变量;除第一次使用指向字符串的指针外,之后的都要使用NULL;注意使用这个函数的时候千万别把指针跟丢了,不然就全乱了。

18、用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

正确答案: #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情:

1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。 3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。

4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。

19、说一说C与C 的内存分配方式?

正确答案: 1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,如全局变量,static变量。

2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3)从堆上分配(动态内存分配)程序在运行的时候用malloc或new申请任意多少的内存,程序员负责在何时用free或delete释放内存。动态内存的生存期自己决定,使用非常灵活。

20、你如何理解MVC。简单举例来说明其应用。

正确答案: MVC模式是observer 模式的一个特例,典型的有MFC里面的文档视图架构。

四、【华为C 面试题】

1、在C 程序中调用被C编译器编译后的函数,为什么要加extern“C”声明?

正确答案: 二者的编译器不同

2、inti=(j=4,k=8,l=16,m=32);printf(“%d”,i);输出是多少?

正确答案: 相当于i=j=4;i=k=8;i=l=16;i=m=32;故最后i=32;

3、#include与#include“file.h”的区别?

正确答案: 相当于i=j=4;i=k=8;i=l=16;i=m=32;故最后i=32;

4、既然C 中有更好的const为什么还要使用宏?

正确答案: 相当于i=j=4;i=k=8;i=l=16;i=m=32;故最后i=32;

5、重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?

正确答案: 从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。重写:是指子类重新定义复类虚函数的方法。从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。重写:当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。

6、C 和C定义结构的分别是什么。

正确答案: Clanguage的结构仅仅是数据的结合Cplusplus的struct和class其实具备几乎一样的功能,只是默认的访问属性不一样而已。

7、#include和#include"a.h"有什么区别?

正确答案: 对于#include,编译器从标准库路径开始搜索a.h对于#include"a.h",编译器从用户的工作路径开始搜索a.h

8、#include和#include“filename.h”有什么区别?

正确答案: 前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。

9、C函数可否单独编译?

正确答案: 外部函数,可以在开始引进来

10、请简述以下两个for循环的优缺点

1)for(i=0;i<n;i ) { if(condition) DoSomething(); else DoOtherthing(); } 2)if(condition) { for(i=0;i<n;i ) DoSomething(); } else { for(i=0;i<n;i )=““dootherthing();=””}=“”

正确答案: 1)优点:程序简洁。缺点:多执行了n-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。

2)优点:循环的效率高。缺点:程序不简洁。

11、完成程序,实现对数组的降序排序

#include voidsort(intarray[]); intmain() { intarray[]={45,56,76,234,1,34,23,2,3};//数字任//意给出 sort(array); return0; } voidsort(intarray[]) {____________________________________ inti,j,k; for(i=1;i<=7;i ){if(array[i]>array[i-1]) { k=ARRAY[i]; j=i-1; do { array[j 1]=array[j]; j–; } while(k>array[j]&&j>=0); array[j 1]=k; } } —————————————————– }

12、delete[]arry和deletearry一样吗?不一样请说明;

正确答案: delete[]arry释放的是多个同一类型的地址空间Delete[]arry释放的是一个某种类型的地址空间

13、结合1个你认为比较能体现OOP思想的项目,用UML来描述。

正确答案: (最好这个项目继承,多态,虚函数都有体现)这个问题大概会占面试时间的一半,并且会问很多问题,一不小心可能会被问住)

14、C与C 各自是如何定义常量的?有什么不同?

正确答案: C中是使用宏#define定义,C 使用更好的const来定义。区别:1)const是有数据类型的常量,而宏常量没有,编译器可以对前者进行静态类型安全检查,对后者仅是字符替换,没有类型安全检查,而且在字符替换时可能会产生意料不到的错误(边际效应)。2)有些编译器可以对const常量进行调试,不能对宏调试。

15、头文件中的ifndef/define/endif干什么用?

正确答案: 防止重复定义

16、C 中为什么用模板类。

正确答案: (1)可用来创建动态增长和减小的数据结构

(2)它是类型无关的,因此具有很高的可复用性。

(3)它在编译时而不是运行时检查数据类型,保证了类型安全

(4)它是平台无关的,可移植性

(5)可用于基本数据类型

17、动态连接库的两种方式?

正确答案: 调用一个DLL中的函数有两种方法:1载入时动态链接(load-timedynamiclinking),模块非常明确调用某个导出函数,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向系统提供了载入DLL时所需的信息及DLL函数定位。2运行时动态链接(run-timedynamiclinking),运行时可以通过LoadLibrary或LoadLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了。

18、在什么时候需要使用“常引用”?

正确答案: 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const类型标识符&引用名=目标变量名;

19、预处理器标识#error的目的是什么?

正确答案: 如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。

20、GCC3.2.2版本中支持哪几种编程语言。

正确答案: 这个问题实在变态,就像问你#error的作用是什么一样。不可否认,gcc是linux下一个亮点,是一个备受无数程序员推崇的编译器,其优点省略1000字,有兴趣可以自己查,我翻了翻书,书上曰:支持C,C ,Java,Obj-C,Ada,Fortran,Pascal,Modula-3等语言,这个“等”比较要命,不过我认为已经很全了,如果认为还是不全,干脆把ASM也加上算了,不过那已经不算是编译了。

五、【小米C 面试题】

1、已知strcpy的函数原型:charstrcpy(charstrDest,constchar*strSrc)其中strDest是目的字符串,strSrc是源字符串。不调用C /C的字符串库函数,请编写函数strcpy。

正确答案: charstrcpy(charstrDest,constcharstrSrc) { if(strDestNULL||strSrcNULL) returnNULL; if(strDest==strSrc) returnstrDest; chartempptr=strDest; while((*strDest =*strSrc )!=‘’) ; returntempptr; }

2.请问运行Test函数会有什么样的结果?

charGetMemory(void) { charp[]=“helloworld”; returnp; } voidTest(void) { charstr=NULL; str=GetMemory(); printf(str); }

正确答案:乱码

3、重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?

正确答案: 从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。重写:是指子类重新定义复类虚函数的方法。从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。重写:当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。

4、多重继承如何消除向上继承的二义性。

正确答案: 使用虚拟继承即可.

5、#include与#include“file.h”的区别?

正确答案: 前者是从StandardLibrary的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

6、对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现?

正确答案: 将操作多个表的操作放入到事务中进行处理

7、#include<filename.h>和#include“filename.h”有什么区别?

正确答案: 查找范围不同,后者先查找工作路径,再查找VC标准路径;前者只查工作路径。

8、预处理器标识#error的目的是什么?

正确答案: 如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。

9、头文件的作用是什么?

正确答案: 1)通过头文件来调用库功能。

2)头文件能加强类型安全检查。

10、请问运行Test函数会有什么样的结果?

voidGetMemory(charp) { p=(char)malloc(100); } voidTest(void) { char*str=NULL; GetMemory(str); strcpy(str,“helloworld”); printf(str); }

正确答案: 程序崩溃了

11、delete[]arry和deletearry一样吗?不一样请说明;

正确答案: delete[]arry释放的是多个同一类型的地址空间Delete[]arry释放的是一个某种类型的地址空间

12、请问运行Test函数会有什么样的结果?

VoidGetMemory(char**p,intnum){ p=(char)malloc(num); } voidTest(void){ char*str=NULL; GetMemory(&str,100); strcpy(str,“hello”); printf(str); }

正确答案: 输出“hello”

13、请简述以下两个for循环的优缺点

//第一个 for(i=0;i<N;i ) { if(condition) DoSomething(); else DoOtherthing(); } //第二个 if(condition) { for(i=0;i<N;i ) DoSomething(); } else { for(i=0;i<N;i ) DoOtherthing(); }

正确答案: 先循环再判断,先判断再循环第一个优点:每个循环都先判断,再执行第二个优点:条件判断,只发生其中一个行为

14、构造函数可否是虚汗数,为什么?析构函数呢,可否是纯虚的呢?

正确答案: 错题解析:构造函数不能为虚函数,要构造一个对象,必须清楚地知道要构造什么,否则无法构造一个对象。析构函数可以为纯虚函数。

15、在C 程序中调用被C编译器编译后的函数,为什么要加extern"C"?

正确答案: C 语言支持函数重载,C语言不支持函数重载。函数被C 编译后在库中的名字与C语言的不同。假设某个函数的原型为:voidfoo(intx,inty);该函数被C编译器编译后在库中的名字为_foo,而C 编译器则会产生像_foo_int_int之类的名字。C 提供了C连接交换指定符号extern"C"来解决名字匹配问题。

16、请写出下面代码在32位平台上的运行结果,并说明sizeof的性质:

#include #include intmain(void) { chara[30]; charb=(char)malloc(20sizeof(char)); printf(“%dn”,sizeof(a)); printf(“%dn”,sizeof(b)); printf(“%dn”,sizeof(a[3])); printf(“%dn”,sizeof(b 3)); printf(“%dn”,sizeof((b 4))); return0; }

正确答案: 在32位系统下(如WIN32),指针长度为32位。a是一个有30个元素的字符型数组;b是一个字符串指针;a[3]是字符型;b 3是指针;*(b 4)是字符型。因此输出:30、4、1、4、1

17、高级通信包括信号量,——-,——–

正确答案: 通常把信号、信号量通信称为低级通信,而把管道、消息队列、共享存储区通信称为高级通信,这个题目我也不知道怎么填了,。。。。。。

18、关联、聚合(Aggregation)以及组合(Composition)的区别?

正确答案: 涉及到UML中的一些概念:关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系;聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系:从实现的角度讲,聚合可以表示为:classA{…}classB{A*a;……}而组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系:实现的形式是:classA{…}classB{Aa;…}

19、尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?

正确答案: 这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是选项:J.Plauger,他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:下面的代码片段的输出是什么,为什么? charptr; if((ptr=(char)malloc(0))==NULL) puts(“Gotanullpointer”); else puts(“Gotavalidpointer”); 这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是“Gotavalidpointer”。

20、请问运行Test函数会有什么样的结果?

voidTest(void){ charstr=(char)malloc(100); strcpy(str,“hello”); free(str); if(str!=NULL){ strcpy(str,“world”); printf(str); } }

正确答案: 错题解析:输出“world”

0 人点赞