基础考查的面试、笔试题

来源:互联网 发布:二阶低通滤波器算法 编辑:程序博客网 时间:2024/05/08 11:14
 1. 指针和引用有什么区别?
引用必须被初始化,指针则不必
存在空指针,但不存在空引用 因为引用相对安全
引用被赋值后不能修改为其它实例的引用,指针被赋值后可以指向其它指针。
2. 堆栈溢出一般是由什么原因引起的?
没做内存释放,递归调用层次过深。
————————————————————详细了解一下调用堆栈的知识。
3. 什么函数不能声明为虚函数?
必须是类的成员函数,像静态函数这些不可以。
构造函数不能声明为虚函数。
——————————————原因————————————————
话说这个问题还引起了同事之间的争议,章老师对编码理解确实相当之深。
我比较认同的原因如下:
虚函数是保存是虚函数表里的,构造函数调用时虚函数表还没有建好,那么没办法进行函数调用。
使用角度,构造函数为虚完全没有必要。虚函数是实现C++多态的一种机制,子类的指针可以赋值给父类指针,父类指针可以通过虚函数调用子类的函数处理逻辑。而构造函数是对象构造的时候调用(且只有在这时候需要调用),只有明确类型时才能调用的到,不会需要通过父类指针去调用。
————————————————————————————————
4. 关于字符串常量的问题
————————————————————详细了解一下
5. 关于一维数组,二维数组指针偏移的问题

从二维数组的角度来看,a代表二维数组的首地址,当然也可以看成二维数组第0行的首地址。
相同于一维数组的表示方法:a+0同样代表第0行的首地址, a+1代表第一行的首地址,a+2代表第2行的首地址,剩下的可以依此类推。
既然把a[0]、a[1]、a[2]看成一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是说,a[0] 代表第0行中第0列元素的地址,即&a[0][0];a[1]是第一行中第0列元素的地址,即&a[1][0];根据地址运算规则,a[0]+1即代表第0行第一列元素的地址,即&a[0][1]。
另外,在二维数组中,还可以用指针的形式来表示各元素的地址。
在一维数组中a[0]与*(a+0)等价,a[1]与*(a+1)等价,因此我们在二维数组中可以这样来表示,即a[i]+j就与*(a+i)+j等价,它表示数组元素a[i][j]的地址。
因此,二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),它们都与a[i][j]等价,或者还可以写成(*(a+i))[j]。

a代表二维数组的首地址,当然也可以看成二维数组第0行的首地址
a+0同样代表第0行的首地址
*(a+0)代表第0行第0列的地址
*a代表第0行第0列的地址
&a代表二维数组的首地址
a[0]代表第0行中第0列元素的地址
&a[0]代表第0行的地址
&a[0][0]代表第0行中第0列元素的地址


main()
{
   int a[5]={1,2,3,4,5};
   int *ptr=(int *)(&a+1);
   printf("%d,%d",*(a+1),*(ptr-1));
}
结果为:2,5 注意&a是数组指针和数组首位指针意义不同,&a+1意为指向数组末尾。
6.
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;

请问
p1+5=______; 0x801000 + sizeof(char)
p2+5=______; 0x810000 + sizeof(long)
7. 做笔试时,需要注意:一定要严谨,指针空值判断,越界处理,const参数等等一定都要想到。
8.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?least = MIN(*p++, b);
#define MIN(A,B) ((A) <= (B) ? (A) : (B))//一定要注意加入所有括号,尤其最外围的括号。===千万不能加分号!!
9. 请说出static和const关键字尽可能多的作用
static关键字至少有下列n个作用:
(1) 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
(2) 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3) 在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
(4) 在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5) 在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

const关键字至少有下列n个作用:
(1) 欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了(2) 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
(3) 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4) 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

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


10. 编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh” 
正确解答1: 

void LoopMove ( char *pStr, int steps ) 

  int n = strlen( pStr ) - steps; 
  char tmp[MAX_LEN]; 
  strcpy ( tmp, pStr + n ); 
  strcpy ( tmp + steps, pStr); 
  *( tmp + strlen ( pStr ) ) = '\0'; 
  strcpy( pStr, tmp ); 


正确解答2: 

void LoopMove ( char *pStr, int steps ) 

  int n = strlen( pStr ) - steps; 
  char tmp[MAX_LEN]; 
  memcpy( tmp, pStr + n, steps ); 
  memcpy(pStr + steps, pStr, n ); 
  memcpy(pStr, tmp, steps ); 
}

11. 关于位域

 网上看了一些资料,发现这里有很多理解上的误区,参考的笔试题答案都是错的。
————————下面主要来自网上资料,原文误区的地方已修改———————————
  有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。
  例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。

一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
        struct 位域结构名
        { 位域列表 };
  其中位域列表的形式为: 类型说明符 位域名:位域长度
例如:
struct bs
{
        int a:8;
        int b:2;
        int c:6;
};

二、位域有如下特性:
        1. 由于位域长度不能大于其对应类型所占空间的位数,如:int 位域长度不能超过32
struct bs
{
        int a:32;
        int b:33;//编译错误
}
        2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。可以是空域,空域表示当前存储单元后面填0,下个位域从下一存储单元开始放置。
例如:
struct k
{
        int a:1;
        int :0;//空域,当前存储单元后面的31位填0——————结构体最开始放置空域是无效的
        int :2;//这2位不用
        int b:3;
        int c:2;
};//该结构体占空间为8字节

三、位域对齐规则:
        1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
        2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
        3. 如果相邻的位域字段的类型不同,则路过当前存储单元,从新类型的存储单元开始分配。

理解了吗?试着做下面几个例子。
#pragma pack(1)
struct s4{
 char a:4;//char存储单元为1字节
 short b:4;//跳过char的1字节,从第2个字节开始分配
 short c:4;//继续向当前short的2字节存储单元分配
 long d;//跳过short的两字节,从第3个字节开始分配,分配4字节
};
输出S4 sizeof:7

#pragma pack(2)
struct s4{
 char a:4;
 short b:4;
 char c:4;
 long d;
};
输出S4 sizeof:8

12. Extern C的含义

以前只知道extern "C"是指定包含的块中为C语言编写的代码,但深究其意义发现其作用如下:
  extern "C"指定其包含的变量、函数为C语言的方式编译、链接。为什么要指定呢?不指定怎么样?
  要做指定的最主要原因在于:C和C++编译上的区别
  C++支持函数重载,C并不支持,所以C++函数被编译后在符号库中的名字与C不同。
————————————————————————————
  如:void add(int a, int b);
  C语言编译后,符号库中名字为_add;而C++编译后,符号库中的名字为_add_int_int(编译器不同会稍有区别)。
————————————————————————————
  在C++中引用示例中的C库,如果未加extern "C"修饰的话,链接时认为头文件对应的是标准C++库。于是在符号库中找_add_int_int接口,显然在原C库中的符号为_add,因为符号找不到链接出错。
  在头文件中对接口加入extern "C"修饰后,编译器就知道接口是定义在C库中,链接时查找_add符号,链接正常。


原创粉丝点击