chunlanse2014

导航

C/C++求职宝典21个重点笔记(常考笔试、面试点)

1、char c = '\72'; 中的\72代表一个字符,72是八进制数,代表ASCII码字符“:”。

\72是8进制数,相当于10进制的58,相当于16进制的\x3a
也就是char a=58,char a='\x3a'也就是 char a=':'
字符':'的值是58

 

2、10*a++ 中a先进行乘法运算再自增(笔试中经常喜欢出这类运算符优先级容易混淆的输出问题)。

优先级

运算符

名称或含义

使用形式

结合方向

说明

1

[]

数组下标

数组名[常量表达式]

左到右

 

()

圆括号

(表达式)/函数名(形参表)

 

.

成员选择(对象)

对象.成员名

 

->

成员选择(指针)

对象指针->成员名

 

2

-

负号运算符

-表达式

右到左

单目运算符

(类型)

强制类型转换

(数据类型)表达式

 

++

自增运算符

++变量名/变量名++

单目运算符

--

自减运算符

--变量名/变量名--

单目运算符

*

取值运算符

*指针变量

单目运算符

&

取地址运算符

&变量名

单目运算符

!

逻辑非运算符

!表达式

单目运算符

~

按位取反运算符

~表达式

单目运算符

sizeof

长度运算符

sizeof(表达式)

 

3

/

表达式/表达式

左到右

双目运算符

*

表达式*表达式

双目运算符

%

余数(取模)

整型表达式/整型表达式

双目运算符

4

+

表达式+表达式

左到右

双目运算符

-

表达式-表达式

双目运算符

5

<<

左移

变量<<表达式

左到右

双目运算符

>>

右移

变量>>表达式

双目运算符

6

>

大于

表达式>表达式

左到右

双目运算符

>=

大于等于

表达式>=表达式

双目运算符

<

小于

表达式<表达式

双目运算符

<=

小于等于

表达式<=表达式

双目运算符

7

==

等于

表达式==表达式

左到右

双目运算符

!=

不等于

表达式!= 表达式

双目运算符

8

&

按位与

表达式&表达式

左到右

双目运算符

9

^

按位异或

表达式^表达式

左到右

双目运算符

10

|

按位或

表达式|表达式

左到右

双目运算符

11

&&

逻辑与

表达式&&表达式

左到右

双目运算符

12

||

逻辑或

表达式||表达式

左到右

双目运算符

13

?:

条件运算符

表达式1? 表达式2: 表达式3

右到左

三目运算符

14

=

赋值运算符

变量=表达式

右到左

 

/=

除后赋值

变量/=表达式

 

*=

乘后赋值

变量*=表达式

 

%=

取模后赋值

变量%=表达式

 

+=

加后赋值

变量+=表达式

 

-=

减后赋值

变量-=表达式

 

<<=

左移后赋值

变量<<=表达式

 

>>=

右移后赋值

变量>>=表达式

 

&=

按位与后赋值

变量&=表达式

 

^=

按位异或后赋值

变量^=表达式

 

|=

按位或后赋值

变量|=表达式

 

15

,

逗号运算符

表达式,表达式,…

左到右

从左向右顺序运算

说明:同一优先级的运算符,运算次序由结合方向所决定。

简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

 

3、const和static的作用 
太常见的问题了,下面给出一个较详细的参考答案:

static关键字:

1)函数体内static变量的作用范围为函数体。不同于auto变量。该变量的内存只被分配一次。因此其值在下次调用时仍维持上次的值。

2)在模块内的static全局变量可以被模块内的所有函数访问。但不能被模块外的其他函数访问。

3)在模块内的static函数只可被这一模块内的其它函数调用。这个函数的使用范围被限制在声明它的模块内。

4)在类中的static成员变量属于整个类所有,对类的所有对象只有一份复制。

5)在类中的static成员函数属于整个类所有,这个函数不接受this指针,因而只能访问类的static成员变量。

const关键字:

1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化。因为以后就没有机会再改变它了。

2)对指针来说,可以指定指针的本身为const,也可以指定指针所指向的数为const。或二者同时为const。

3)在一个函数的声明中,const可以修饰形参,表明它是一个输入参数。在函数内不能改变其值。

4)对于类的成员函数,若指定其为const类型,则表明其是一个常量函数。不能修改类的成员变量。

5)对于类的成员函数,有时候必须指定其返回值为const类型。以使得其返回值不为“左值”。

 

4、注意sizeof不是函数而是运算符,所以在计算变量所占用空间大小时,括号是可以省略的,但在计算类型大小时括号则不能省略,比如int i = 0; 则sizeof int是错误的。

 

5、有1,2,…,n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。

 1 #include <stdio.h>
 2 
 3 int main() 
 4 {
 5     int a[] = {10, 6, 9, 5, 2, 8, 4, 7, 1, 3};
 6     int i, tmp;
 7     int len = sizeof(a) / sizeof(a[0]);
 8     for(i = 0; i < len;) 
 9     {
10         tmp = a[a[i] - 1];
11         a[a[i] - 1] = a[i];
12         a[i] = tmp;
13         if(a[i] == i + 1) 
14             i++;
15     }
16     for(i = 0; i < len; ++i)
17         printf("%d ", a[i]);
18     printf("\n");
19     return 0;
20 }

分析如下:

(初始) 10,6,9,5,2,8,4,7,1,3
a[a[i] - 1]=3
(1) 3,6,9,5,2,8,4,7,1,10
a[a[i] - 1]=9
(2) 9,6,3,5,2,8,4,7,1,10
a[a[i] - 1]=1
(3) 1,6,3,5,2,8,4,7,9,10
因为a[i]=1所以i++,
于是a[a[i] - 1]=8
(4) 1,8,3,5,2,6,4,7,9,10
a[a[i] - 1]=7
(5) 1,7,3,5,2,6,4,8,9,10
a[a[i] - 1]=4
(6) 1,4,3,5,2,6,7,8,9,10
a[a[i] - 1]=5
(7) 1,5,3,4,2,6,7,8,9,10
a[a[i] - 1]=2
(8) 1,2,3,4,5,6,7,8,9,10
a[a[i] - 1]=2,结束

 

6、易误解:如果int a[5],那么a与&a是等价的,因为两者地址相同。 
解答:一定要注意a与&a是不一样的,虽然两者地址相同,但意义不一样,&a是整个数组对象的首地址,而a是数组首地址,也就是a[0]的地址a的类型是int[5],a[0]的类型是int,因此&a+1相当于a的地址值加上sizeof(int) * 5,也就是a[5],即下一个对象的地址,已经越界了,而a+1相当于a的地址加上sizeof(int),即a[1]的地址。

 

7、如何将一个小数分解成整数部分和小数部分? 
要记得利用头文件中的库函数modf,下面是函数原型(记住一些实用的库函数,避免自己重写):

1 double modf(double num, double *i); // 将num分解为整数部分*i和小数部分(返回值决定)

 

8、可作为函数重载判断依据的有:参数个数、参数类型、const修饰符; 
不可以作为重载判断依据的有:返回类型。

 

9、程序输出题:

1  int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
2  int *p = &(a + 1)[3];
3  printf("%d\n", *p);

输出:5 
说明:因为a+1指向a的第二个元素,[3]表示再向后移动3个元素。

 

10、程序输出题:

 1 char str1[] = "abc";
 2 char str2[] = "abc";
 3 const char str3[] = "abc";
 4 const char str4[] = "abc";
 5 const char *str5 = "abc";
 6 const char *str6 = "abc";
 7 char *str7 = "abc";
 8 char *str8 = "abc";
 9 cout << (str1 == str2) << endl;
10 cout << (str3 == str4) << endl;
11 cout << (str5 == str6) << endl;
12 cout << (str7 == str8) << endl;

输出:0 0 1 1 
说明:输出str1~str8的地址为:

0x23aa80 
0x23aa70 
0x23aa60 
0x23aa50 
0x23aa48 
0x23aa40 
0x23aa38 
0x23aa30

输出str1~str8内容“abc”的存储地址为:

0x23aa80 
0x23aa70 
0x23aa60 
0x23aa50 
0x100403030 
0x100403030 
0x100403030 
0x100403030

可以发现str1~str4中的内容是存在栈上,地址各不相同,而str5~str8的内容都是存储在常量区,所以地址都相同。

注意:

1 char *str1 = "abc";
2 printf("%p\n", str1);  
3 cout << &str1 << endl;

上面打印的是字符串 “abc”的地址,下面打印的是 str1 变量的地址。

 

11、C的结构体和C++结构体的区别

(1)C的结构体内不允许有函数存在,C++允许有内部成员函数,且允许该函数是虚函数。所以C的结构体是没有构造函数、析构函数、和this指针的。 
(2)C的结构体对内部成员变量的访问权限只能是public,而C++允许public,protected,private三种。 
(3)C语言的结构体是不可以继承的,C++的结构体是可以从其他的结构体或者类继承过来的。

以上都是表面的区别,实际区别就是面向过程和面向对象编程思路的区别:

C的结构体只是把数据变量给包裹起来了,并不涉及算法。 
而C++是把数据变量及对这些数据变量的相关算法给封装起来,并且给对这些数据和类不同的访问权限。 
C语言中是没有类的概念的,但是C语言可以通过结构体内创建函数指针实现面向对象思想。

 

12、如何在类中定义常量成员并为其初始化? 
解答:只能在初始化列表里对const成员初始化,像下面这样:

1 class CBook 
2 {
3 public:
4      const double m_price;
5      CBook() :m_price(8.8) { }
6 };

下面的做法是错误的:

1 class CBook 
2 {
3 public:
4     const double m_price;
5     CBook() 
6     {
7         m_price = 8.8;
8     }
9 };

而下面的做法虽未报错,但有个warning,也不推荐:

1 class CBook 
2 {
3 public:
4     const double m_price = 8.8; // 注意这里若没有const则编译出错
5     CBook() { }
6 };

 

13、在定义类的成员函数时使用mutable关键字的作用是什么? 
解答:当需要在const方法中修改对象的数据成员时,可以在数据成员前使用mutable关键字,防止出现编译出错。例子如下:

 1 class CBook 
 2 {
 3 public:
 4     mutable double m_price;  // 如果不加就会出错
 5     CBook(double price) :m_price(price) { }
 6     double getPrice() const; // 定义const方法
 7 };
 8 double CBook::getPrice() const 
 9 {
10     m_price = 9.8;
11     return m_price;
12 }

 

14、构造函数、拷贝构造函数、析构函数的调用点和顺序问题,如下面这个例子输出是什么?

 1 class CBook 
 2 {
 3 public:
 4     CBook() 
 5     {
 6         cout << "constructor is called.\n";
 7     }
 8     ~CBook() 
 9     {
10         cout << "destructor is called.\n";
11     }
12 };
13 
14 void invoke(CBook book) 
15  /** 对象作为函数参数,如果这里加了个&就不是了,因为加了&后是引用方式传递,形参和实参指向同一块地址,就不需要创建临时对象,也就不需要调用拷贝构造函数了*/
16 {  
17     cout << "invoke is called.\n";
18 }
19 
20 int main() 
21 {
22     CBook c;
23     invoke(c);
24 }

解答:注意拷贝构造函数在对象作为函数参数传递时被调用,注意是对象实例而不是对象引用。因此该题输出如下:

constructor is called.
invoke is called.
destructor is called.  // 在invoke函数调用结束时还要释放拷贝构造函数创建的临时对象,因此这里还调用了个析构函数
destructor is called.  

引申:拷贝构造函数在哪些情况下被调用? 
(1)函数的参数为类对象且参数采用值传递方式; 
(2)将类对象做为函数的返回值。

 

15、C++中的explicit关键字有何作用? 
解答:禁止将构造函数作为转换函数,即禁止构造函数自动进行隐式类型转换。 
例如CBook中只有一个参数m_price,在构建对象时可以使用CBook c = 9.8这样的隐式转换,使用explicit防止这种转换发生。

 

16、在C++中,如果确定了某一个构造函数的创建过程,在该构造函数中如果调用了其它重载的构造函数,它将不会执行其它构造函数的初始化列表部分代码,而是执行函数体代码,此时已经退化成普通函数了。例子说明如下:

 1 class CBook 
 2 {
 3 public:
 4     double m_price;
 5     CBook() 
 6     {
 7         CBook(8.8);
 8     }
 9     CBook(double price) : m_price(price) { }
10 };
11 int main() 
12 {
13     CBook c;
14     cout << c.m_price << endl;  // 此时并不会输出理想中的8.8
15 }

 

17、静态数据成员只能在全局区域进行初始化,而不能在类体中进行(构造函数中初始化也不行),且静态数据成员不涉及对象,因此不受类访问限定符的限制。 
例子说明如下:

1 class CBook 
2 {
3 public:
4     static double m_price;
5 };
6 double CBook::m_price = 8.8;  // 只能在这初始化,不能在CBook的构造函数或直接初始化

 

18、C++中可以重载的运算符:new/delete、new[]/delete[]、++等。 
不可以重载的运算符 :"."、"::"、"?:"、"sizeof"、"typeid"、"**"、不能改变运算符的优先级。

引申:重载++和--时是怎么区分前缀++和后缀++的? 
例如当编译器看到++a(先自增)时,它就调用operator++(a); 
但当编译器看到a++时,它就调用operator++(a, int)。即编译器通过调用不同的函数区别这两种形式。

 

19、C++的多态性分为静态多态和动态多态。 
静态多态性:编译期间确定具体执行哪一项操作,主要是通过函数重载和运算符重载来实现的; 
动态多态性:运行时确定具体执行哪一项操作,主要是通过虚函数来实现的。

 

20、虚函数原理考点,例如下面程序的输出是什么?

 1 class A 
 2 {
 3 public:
 4     virtual void funa();
 5     virtual void funb();
 6     void func();
 7     static void fund();
 8     static int si;
 9 private:
10     int i;
11     char c;
12 };

问:sizeof(A) = ?

解答: 
关于类占用的内存空间,有以下几点需要注意: 
(1)如果类中含有虚函数,则编译器需要为类构建虚函数表,类中需要存储一个指针指向这个虚函数表的首地址,注意不管有几个虚函数,都只建立一张表,所有的虚函数地址都存在这张表里,类中只需要一个指针指向虚函数表首地址即可。 
(2)类中的静态成员是被类所有实例所共享的,它不计入sizeof计算的空间 
(3)类中的普通函数或静态普通函数都存储在栈中,不计入sizeof计算的空间 
(4)类成员采用字节对齐的方式分配空间

答案:12(32位系统)或16(64位系统)

 

21、虚继承的作用是什么? 
在多继承中,子类可能同时拥有多个父类,如果这些父类还有相同的父类(祖先类),那么在子类中就会有多份祖先类。例如,类B和类C都继承于类A,如果类D派生于B和C,那么类D中就会有两份A。为了防止在多继承中子类存在重复的父类情况,可以在父类继承时使用虚函数,即在类B和类C继承类A时使用virtual关键字,例如: 
class B : virtual public A 
class C : virtual public A 
注:因为多继承会带来很多复杂问题,因此要慎用。

posted on 2015-05-05 09:37  chunlanse2014  阅读(179)  评论(0编辑  收藏  举报