C++工程师面试宝典系列之C/C++经典面试题

1.const 的全面理解:

(1)说说你对const 的理解(主要C语言范围内)

const是一个C中类型修饰符;

常见的类型修饰符有:short,long,unsigned,signed,static,auto,extern,register,volatile;

定义一个变量:类型描述符  变量名;

类型描述符包括:类型的修饰符以及数据类型 int  char  float ......

1)类型描述符中如果有多个关键字,它们出现的位置不影响他对变量的限制:

short  int  i;

int   short   i;

static  int  short   i;

int  static  short  i;

(2)下面的声明都是什么意思?

const  int   a

int   const   a

以上完全一样,描述的都是一个const的整型变量。

const   int   *a

int*   const   a

int   const*   const  a

对指针变量类型的理解:

1).   []  ()  *  在数据定义时与在表达式中优先级一样的理解。例如:

int  *a[10]     //因为 [] 的优先级 高于* ,因此是一个数组,每个成员类型为指针,指向int

int  (*a)[10]    //因为()的优先级高于[] ,因此,先看里面,是一个指针,指向的类型为一个数组

2).   指针的判断从右向左:

const   int   *a     //a是变量名,*表示它是一个指针(类型已经确定),余下的是指向的类型;

    //因此,a是一个指向const int 的指针,即指向的数据不可修改;

int*   const   a    // *const一起来修饰a,即a只读,*表示a是一个指针,因此,这是一个只读指针,指向的类型为int型                             //  的变量

int   const    *const  a   // *表示指针,因此指针不可修改,int const是指针指向的类型,仍然是const;


(3)

typedef   void*   VP;

(a)const   void   *ptr存储位置;

(b)const   VP  ptr存储位置;

首先要理解typedef是定义一种数据类型,一定要与define区分开;

typedef   void*   VP;     //  VP是名字,余下的是这个类型的真实类型

const  VP  ptr;    //  是不是替换为const  void  *ptr;??不是,void*是一个整体

                            //    const  int  i;  ==  int  const  i;

                            //    VP  const  ptr;  即 void  *const ptr;

(4)为什么还在编程中全用const?

1).向其他程序员传递一个信息。这个不要修改。

2).有可能让编译器产生更精简紧凑代码,减少bug。

3).合理的保护我们只读的数据,避免不必要的错误。

使用位置:

1)定义常量,防止被修改;

2)函数的参数中,如果不期望子函数去修改被调用函数的某个数据,可以加以限制。例如:

char  *strcpy(char  *dest , const  char  *src);

char  *strcpy(char  *dest,const  char  *src,size_tn);

3) 在C++中,类的成员函数的使用。

=======================================================================================

2. sizeof 是函数吗?准确的列出sizeof() 的功能。以下代码中(32位平台):

int  a[10];

int   *ptr;

以下内容作为右值时,是否正确,如果正确,值为多少?

sizeof(a)

sizeof(a[10])

sizeof(a[1])

sizeof(ptr)

sizeof(*ptr)

sizeof(int)*ptr

(1)谈谈你对sizeof 的理解。

sizeof不是函数,C语言的一个关键字,作为右值时,求某个数据类型(sizeof(int))或某个变量对应的数据类型sizeof(a)来定义某个变量时,在当前平台下所需要占用内存空间的大小。并不是真正求某个变量本身的内存空间大小,也不会涉及到对这个空间的访问。

sizeof(a)               // 找到a的类型,int[10]是a 的类型,因此是一个数组,相当于sizeof(int[10]),值40(32位平台)

sizeof(a[10])        // a[10]本身是一个越界访问,但是,这里并不是去访问a[10]的空间大小,而是求它的类型

      // a[10]  ---->  *(a+10) 即a指向的类型,即int型,因此,求的是sizeof(int)即4个字节。

sizeof(a[1])          //  同上,4字节。

sizeof(ptr)           //  指针本身类型占用空间大小,32位平台4个字节。

sizeof(*ptr)          //  ptr指向的数据类型,因此为int型,4个字节。

sizeof(int)*ptr      //  编译出错的。sizeof(int), *ptr取内容, 中间没有运算符。

=======================================================================================

3.static 的理解

#include<stdio.h>
int counter(int i){
     static int count = 0;
     count = count + i;
     return(count);
}
main(){
     int i,j;
     for(i=0;i<=5;i++)
     {
            j=counter(i);
            printf("i:%d\n,j:%d\n,i,j");
     }
}

(1)列出所有你对static的理解。

(2)谈谈你对static的理解(C部分,或者C++部分)。
解题思路:

static定义的数据存放的区域,怎么初始化?以及它的生存周期和作用域的问题。

本题中,static所在行定义一个静态的局部变量(已经初始化),值存放在数据段中,生存周期是从程序运行到程序结束。

参数 int i 这一行,定义一个普通的变量,存储类型实际为auto,因此,每进入一次这个函数,重新定义这个变量,退出这个函数,这个变量的空间释放掉。

关于static的理解。首先明确数据的存储类型和可执行文件的段域问题(具体可查阅C部分关于存储问题的资料)

1)定义一个静态的变量。对应要理解auto存储类型。初始化,生存周期,作用域。

static int i =10;   // 局部或者全局

2)定义一个函数的时候。在当前的文件中可以访问,这个函数作用域为当前文件(模块)。

static  int  fun();

3)C++中,类的成员定义时,有静态成员变量和静态成员函数。

class A
{
private:
	static  int  s_value;
};

int  A ::  s_value = 0;       //初始化

这个成员不属于类的对象,而属于类。对它的访问,全用类。例如 A :: s_value。

静态成员函数:

class A
{
private:
          static  void  func(int value);
};
强调一点: 同样是属于这个类,只能访问类的静态的成员变量,不能访问对象的其他数据。
补充题目:如何在头文件中声明一个全局变量?能够初始化吗?

如果在头文件中定义了一个静态变量,因为静态变量只属于某个文件,如果多个.c 的文件包含了这个头文件,实际上相当于定义了多个静态成员变量(每个文件一个)

如果在头文件中定义一个全局变量,如果被多个.c 的文件包含的话,要这样用:

在*.h中

extern  int  g_value;   //注意,不要初始化值!

然后各个.c 的文件包含,同时在某个.c 的文件初始化。

=======================================================================================

4.volatile的全面理解

#include  <setjmp.h>
#inc;ude <stdio.h>
#include <stdlib.h>
static jmp_bufbuf;
main()
{
int a;
volatile int b;
a=2;
b=3;
if(setjmp(buf)!=0)
{
	printf("a:%d,b%d\n",a,b);
	exit(0);
}
a=5;
b=5;
longjmp(buf,1);
}

gcc -o volatile volatile.c -O3

使用优化编译后,输出的结果是什么?


(1)谈谈你对volatile的理解。

(2)volatile可以应用到哪些地方。

考点分析:

(1)对setjmp和longjmp的理解。

(2)对编译优化的理解以及对volatile的理解。

解题思路:

int setjmp(jmp_bufenv);

void longjmp(jmp_bufenv,int val);

用于跳转,setjump设置一个跳转栈位置,longjmp执行跳转到最近一个setjmp位置。


volatile到底用在哪些地方?volatile到底表示什么意思?

表示这个变量时易变的。实际是要求编译器每次直接读取原始的内存址而去掉所有的优化。

在嵌入式开发的寄存器数据定义时经常使用。

#define  CONDATA   *((volatile  int *)0x80000000)

volatile的应用位置:

1)硬件寄存器数据访问时,如果这个寄存器的数据有可能被硬件修改。一定使用volatile来定义这个变量。

2)中断服务程序中一些非自动变量。

3)在多线程中被几个线程共享的数据。


其他问题:

1)一个参数既可以是const还可以是volatile吗?解释为什么。

2)一个指针可以是volatile吗?解释为什么。

3)下面的函数有什么错误:

int  square(volatile  int  *ptr)
{
	return  *ptr  **ptr;
}
=======================================================================================

5.数据类型限制

(1)double和float的精度分别是?float变量与零值比较

(2)请问下面程序有什么错误?如何改正?

#define  Max_CB  500
void  LmiQueryCSmd(Struct  MSgCB  *pmsg)
{
unsigned  char  ucCmdNum;  //unsigned char 范围是0~255,不可能超过500,所以for循环是一个死循环
......
for(ucCmdNum = 0;ucCmdNum<Max_CB;ucCmdNum++)
{
......
}
}


(3)0 的理解

评价下面代码片段是否正确:

unsigned  int  zero = 0;
unsigned  int compzero = 0xFFFF;
/*1 's complement of zero*/
相关题目:

(1)详细阐述浮点型数据在计算机中的存放方式。

考点分析:

(1)C语言的基础知识。数据类型的限制。

(2)是否深究技术细节。

解题思路:

首先要理解在任何平台下,任何数据类型都是有范围限制。在Linux平台限制的文件是:

limits.h(限制与整型相关的数据类型的范围)

unsigned  int 型与当前的平台相关0~2^32-1

int  -2^31~2^31-1

float.h(限制与浮点型相关的数据类型的范围)。find/usr/-name float.h


(1)double和float的精度分别是?float变量与零值比较

float  4 BYTE:1 bit 符号位+8 bit 指数位 + 23 bit 的有效数值位;
double  8 BYTE:1 bit 符号位 + 11 bit 的指数位 +52 bit 的有效数值位;

(a)没有unsigned float 和 signed float的用法;

(b)表示范围由指数位决定;

(c)有效位由尾数有效值数值位决定。

float  23bit:最大为2^23转换成十进制最多有7位有效位,但只能保证6位有效位。

double 同理,15~16(十进制)个有效精度。

float  f;
if(f != 0)     //不可以的

#define  EPSINON  0.00001    //定义一个宏
if ((f >= -EPSINON) && (f <= EPSINON))
=======================================================================================
6.++运算符的疑惑

(1)

int  i=3;

int  j=(++i)+(++i)+(++i);   //  ( 5 + 5 )+6

int  k=(i++)+(i++)+(i++);

求i,j,k的值。

i:6;   j:16;   k:9;

(++i) + (++i)中的++完成后,“+”运算符已经可以执行,因此立即执行。因此,所谓的++在前,先执行++,再执行其他运算是在一个表达式内这样理解。并不需要到语句的结束。

而++在后面,整个语句结束后再执行++操作。

(2)下面的结构是合法的吗?如果是它做些什么?

int  a=5,b=7,c;

c=a++ +b;          //贪心法:一个变量期望尽可能多的关联运算符。

求a,b,c的值。

a:6; b:7; c:12

(3)自加操作(++)

main()
{
	int i=3;
	int j;
	j=sizeof(++i+++i);     //不加空格会是什么情况;
	printf("i=%d j=%d",i,j);
}
这段程序的输出是?

i:3; m:4;

在这里sizeof 求的是对应类型,并不会执行相应的运算。

另外,++i++i出错的原因?

因为贪心算法,++i+++i 理解为++i++  +i,即:

++i++理解为:++i = i++,++i为左值是不允许的,编译出错。

考点分析:

(1)C语言的基础知识。编译环境的熟悉。

(2)是否深究技术细节。

解题思路:

++/-- 在变量前和变量后区别很大:

在前面:++a,先执行++(执行到下一个操作符可以完成操作执行时),再执行其他操作;编译器的约定需要关注。

在后面:a++,先执行其他操作,在执行++。

=======================================================================================

7.逻辑运算符的短路问题

int i=1;
int j=0;
if((i++>0) || (++j>0))            //i++ = 1结果为真了,不会继续判断,输出时 i++ =2,j =0;
;
printf("i:%d,j:%d\n",i,j);

i:2; j:0;

考点分析:

(1)C语言基础知识。编译环境的熟悉。

(2)是否深究技术细节。

解题思路:

遇到这个题目不要考虑得太简单,一个面试题一定有考察的地方。

逻辑与 A&&B

逻辑或 A||B

=======================================================================================





































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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值