程序员面试问题精选

题目来自程序员面试宝典及我在面试笔试过程中遇到的一些疑难点

 

++与函数参数进栈
int array[]={1,2,3,4,5}
int *ptr=array;
*(ptr++)+=123;
printf("%d,%d",*ptr,*(++ptr));
结果为输入:3,3

 

类型转换与地址
float i=1.0f
cout<<(int) i<<endl;    //output 1
cout<<&i<<endl;  //output address of i
cout<<(int&)i<<endl;    //output first 32 bit value of float i's memory address 1065353216
cout<<( (int)a == (int&)a )<<endl; //output false

 

类型转换与指针
unsigned int a=0xfffffff7;
unsigned char i=(unsigned char) a; //i是a被截断的前8位
char *p=(char*)&a;     //p是指向&a类型的指针
printf("%08x,%08x/n",i,*p);        //cout 000000f7,fffffff7

 

int main(int argc, char* argv[]) { int a[2][3]={0,8,2,3,4,5}; int** p; p = (int**)a; cout<<*(p+1)<<endl; //0x00000008 return 0; }

假设数组a的地址为x,则p+1=x+sizeof(int*)=x+4,(p+1)指向8,对(p+1)解引用取到8,但p为指向指针的指针,因此输出为地址形式的0x00000008。

 

与或非应用
使用一个表达判断x是否为2的幂:(x>0)&&!(x&(x-1))

x is odd                                               return  (x&1)==1
求一个数的2进制表示中1的个数 m=$1;while(m) {cnt++;m=m&(m-1);} return cnt;
交换a b:a=a^b;b=a^b;a=a^b;

              a = a+b-(b=a) 

 

不使用判断的方法求两个数中的大数:return (a+b)/2+abs(a-b)/2

 


sizeof
struct {long a;char b;}A;     //sizeof(A)=8;
char *p="0123456789";     //sizeof(p) =4
char str[]="0123456";        //sizeof(str)=7
char q[]="a/n";                   //sizeof(q)=3
bool val;                              //sizeof(val)=1
                                           //sizeof(float)=4
                                           //sizeof(double)=8
int fun(){...}                       //sizeof(fun)=4
                                          //sizeof(string)=4
string array[4]                   //sizeof(array)=16
class A {};                        //sizeof(A)=1; see c++ obj modeule


内联比宏的优势是:前者要做类型检查。

 

指针和引用
指针可以为空而引用必须在声明时初始化指向某个对象,因此引用在使用时不需要合法性检查。
引用一旦初始化就不能修改,注意的是引用对象的内容可以修改。因此加const限定时,只有一种情况,即const 引用,它是指指向const对

象的引用。int & const p =a 就是 int& p=a; 而const int& p=a表示const int a.
而指针加const限定时就有两种表示意义,int const *p=&a 表示指针指向的内容不能修改,而int* const p=&a就表示指针本身不能再指向其他对象。复合起来就有 const int* const p =&a同时限定了两者都不能被修改。

 

形参与指针
int a[10];
fun(a){
 cout<<sizeof(a); //4
}

void getmem(char* p,int n)
{
 p=(char*)malloc(n);  //形参p无法修改str的值
 //return p;
}

int main()
{
 char *str=NULL;
 getmem(str,10);      //str=NULL
 //str=getmem(10)
 strcpy(str,"hello");
 free(str);
}

 

字符串常量指针
const char* fun()
{
 char str[]="hello world";  //wrong str in stack
 //char* str="hello world"; //right str in global store zone 
 return str;    
}

 

函数、指针与数组
int* a[10]       //数组a[10],每个元素为int型指针
int** a[3][4]   //sizeof(a)=48 a is array a[i][j] is a ptr of ptr
int (*a)[10]     //a为指向一维数组的指针,数组元素为int型
int (**a)[10]  //a为二级指针,它指向一个指向一给数组的指针
int* (*a)[10]    //a为指向一维数组的指针,数组元素为int*型
int (*a[10])()   //a是一维数组,每个元素都是一个返回值为int的函数指针,函数没有形参
int *((*a)[10])  //同int* (*a)[10]
int (*a)(int)    //a是函数指针,指向函数带一个int形参
int (*(*f)(int,int))(int)  //f为函数指针,指向一个函数fun(int,int),而fun返回值也为函数指针,且类型为int fun(int);

 

malloc/free 与 new/delete
前者是库函数,只申请空间,后者是操作符对于类类型的操作,后者会进行构造与析构操作。

 

指针与句柄
指针指向物理地址?
句柄是指向一个对象的地址,而这地址会由于对象对内存管理操作进行移位而改变。

 

智能指针
智能可以在离开作用后自动析构,并在异常抛出时进行对象的析构,从而防止内存泄露。


类的成员变量
类的静态成员变量可以是公有也可是私有,类的静态成员只能在类的外部初始化。T class::s_mem=0.
如果没有初始化,则不能通过编译。类的静态成员变量及函数只具有文件作用域。

类的常量成员,只能在构造函数的初始化列表里初始化。

 

重载与重写
重载是指同一个函数具有不同的参数或限定词,重载是由编译器静态完成的,不需要动态完成,与面向对象无关。
重写是指基类的虚函数在派生类中被重新实现的过程。函数的参数与返回值没有改变。重写通过虚函数实现了多态。

 


访问控制
public private protected
作用于类的成员时,public成员表示它对类外部可见,private成员表示成员对类外部不可见,只能在类的内部使用,而且对子类也不可见,

而protected成员对类外部不可见,但对子类可见。
继承体系中修饰类时,public继承表示子类可以访问父类中的非private成员, 也可以通过子类对象访问基类的非private成员。private继承

表示子类的对象不能访问基类的所有成员,但在子类中可以访问基类的非私有成员。protected继承与私有继承类似,在子类中可以访问基类

的非私有成员,子类对象可以访问基类的非private成员,这些成员继承后成为protected,且不能再子类的子类访问。
private继承和protect继承只在讨论上有用,并不见与软件设计。
如果在继承中没有使用关键字,则默认是私有继承。

 

位运算与嵌入式
int main()
{
     int a=5; double b=5.01;
     printf("%f/n",a);      //xxxxx
     printf("%d/n",b);   //1889785610
}
对于printf函数而言,输出%f时,参数应该为double类型,如果参数为非double的,则会从栈中读出8B解释。而对于%d,如果参数为double

型的,则只解释前4位部分。

 

设置某位的方法
# define BITN (0x1<<N)
void set_bitn(int *p)
{
     *p=*p|BITN; 
}

void clr_bitn(int* p)
{
     *p&=~BITN
}

 

中断服务程序(ISR)要求没有参数,没有返回值,不进行浮点计算,不使用printf这类存在重入问题的函数。

 

直接内存地址访问
int *ptr;
ptr=(int*)0x679a;
*ptr=1;

 

malloc(0)将返回一个非NULL的有效指针。

 

判断CPU大小端的方法
int x=1;
if(*(char *)&x==1)
 //little endian
else
 //big endian

 

位域的赋值

#include "stdio.h" #include "stdlib.h" #include <bitset> #include <iostream> using namespace std; union V { struct X { unsigned char s1:2; unsigned char s2:3; unsigned char s3:3; } x; unsigned char c; } v; int main() { v.c = 100; printf("%d %d %d/n", v.x.s1,v.x.s2,v.x.s3); bitset<8> uchar(100); cout<<uchar<<endl; }  

结果输出为01100100

0 1 3 

就是说,单个字节中的位域划分是从低位到高位的,这样,s1使用低两位的00,s2使用中间两位001,而s3使用高两位011

 

 

变量内存分配
进程在内存中分为三部分:代码段、静态数据区、动态数据区。
动态数据区一般指堆栈,存放自动变量等,静态数据区在另一块区域,存放着全局变量与静态变量。

内存分配函数new
对于基本数据类型的内存分配,操作系统已经记录了分配内存空间的大小,而对于带有析构函数的类类型的内存分配,还要记录调用析构函数的次数,因此有额外的4字节用来记录数组的大小。此外在Windows系统中,new一块内存的后面还有4个字节在后面作为内存分配边界。

 

进程间通信的方法:信号、信号量、消息队列、共享内存

 

RAID分类
0  多个磁盘组成一块大硬盘,并行操作,无冗余特性。磁盘利用率为n
1  主盘与镜像盘,同时操作。磁盘利用率最低1/2
3  使用一个单独的磁盘存放其他磁盘的校验数据,当其他磁盘出错时,借助校验数据恢复,但校验盘出错则其他盘数据都无法使用,磁盘利用率为n-1。
5  校验磁盘分散在各块磁盘上。安全性最高,磁盘利用率为n-1
0-1 并行磁盘操作,同时一半磁盘做为镜像。

你可能感兴趣的:(面试,struct,String,float,fun,磁盘)