现在的位置: 首页 > 综合 > 正文

面试总结与分析(一)

2013年10月20日 ⁄ 综合 ⁄ 共 6144字 ⁄ 字号 评论关闭

一,找出程序中的错误

int set(char*strDest,const char*str)

{  char string[10];
    char* str1 = "0123456789";

    strcpy(string,str1);

}

这个属于数组越界的错误

数组越界错误,主要表现在这几个方面:
1,分配数组没有以/0结尾,计算数组大小时,导致用函数strlen去取大小时不是预料中的大小;
2,定义数组时,没有memset,而直接采用数组最后一位下标赋值为0的方法,虽然比memset高效,但是往往下标越界,导致错误;
3,分配数组大小时,没有考虑特殊情况,往往想当然;或者开始想好了,但是决策变化,但是数组的大小分配仍然没有变化,导致数组越界错误;
4,另外,关于越界问题,类型的分配不对,unsigned short 最长只能65535,如果超过此长度,也会导致越界问题;
介于此:
1,每次分配数组大小时,估计的数组大小要比原来大小大1个字节,用于/0截断字串;
2,在性能要求不太重要时,memset往往比下标赋值安全;
3,在数组分配大小时,最好采用定义变量值的方式或者动态分配大小,定义变量值能够是决策发生变化时,很容易修改代码,动态分配容易除了能够节省内存外,还能找出隐藏的越界问题;
4,对于类型的越界问题,需要多用valgrind等内存检查工具来检测,另外,注释你所写的代码来检查代码发生错误的地方也不失一种检查代码的好办法。
二,#define ,#ifdef ,#endif有什么不同
#define 用于宏定义 ;#ifdef表示条件编译 ;#endif 结束符
三,Cplusplus是什么?
C++,这个词在中国大陆的程序员圈子中通常被读做“C加加”,而西方的程序员通常读做“C plus plus”
 
四,用最有效率的方法算出2乘以8
    通常如果需要乘以或除以2的n次方,都可以用移位的方法代替,大部分的C编译器,用移位的方法得到代码比调用乘除法子程序生成的代码效率高。
 16 可以有2左移3位获得:2<<3,
除2 = 右移1位               乘2 = 左移1位 
除4 = 右移2位               乘4 = 左移2位
除8 = 右移3位               乘8 = 左移3位

实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:

a=a*9
分析a*9可以拆分成a*(8+1)即a*8+a*1, 因此可以改为:    a=(a<<3)+a

a=a*7
分析a*7可以拆分成a*(8-1)即a*8-a*1, 因此可以改为:    a=(a<<3)-a

 

五,static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别? 

   C语言把作用域分为全局和局部两种:只能在函数或语句中起作用的变量,称局部变量或内部变量。可以再一个文件范围或一个程序的所有文件范围内起作用的变量,称为全局变量。

  变量的生存期指变量何时被创建,何时被撤销。 先看下C语言对程序的存储分配。 c把执行程序所占用的内存空间(称用户区)分为3部分:程序区,静态存储区和动态存储区。变量被分配在静态和动态2个区中。

   存储在静态存储区中的变量,在编译时即被创建,在程序运行结束时才被撤销,相对于程序的生命而言,其生命史永久的。   存储在动态存储区中的变量,在程序运行过程中被动态创建,在程序运行完所在的域即被撤销,相对于程序而言,其生命史暂时的。

      从以上分析可以看出,   把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,   限制了它的使用范围。  
  static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件  
  static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;  
  static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;

 

六,局部变量能否和全局变量重名?  
  答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: "  
  局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。 

 

七,#include<文件名>与#include"文件名 ",的区别

查找头文件的方式不同:<>是先到系统目录里面去查找这文件,称为标准方式; “”是先到用户当前文件目录中查找,如没找到在使用标准方式查找。   一般用户定义的文件使用方式2查找效率要快点

 

八,sizeof()的应用

sizeof()功能:计算数据空间的字节数
1.与strlen()比较
      strlen()计算字符数组的字符数,以"/0"为结束判断,不计算为'/0'的数组元素。
      而sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示。
2.指针与静态数组的sizeof操作
      指针均可看为变量类型的一种。所有指针变量的sizeof 操作结果均为4。
注意:int *p; sizeof(p)=4;
                  但sizeof(*p)相当于sizeof(int);      
      对于静态数组,sizeof可直接计算数组大小;
      例:int a[10];char b[]="hello";
              sizeof(a)等于4*10=40;
              sizeof(b)等于6;
 注意:数组做型参时,数组名称当作指针使用!!
               void  fun(char p[])
               {sizeof(p)等于4}    
经典问题: 
      double* (*a)[3][6]; 
      cout<<sizeof(a)<<endl; // 4 a为指针
      cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组
      cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针
      cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针
      cout<<sizeof(****a)<<endl; // 8 ****a为一个double变量
问题解析:a是一个很奇怪的定义,他表示一个指向double*[3][6]类型数组的指针。既然是指针,所以sizeof(a)就是4。 
      既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)=3*6*sizeof(double*)=72。同样的,**a表示一个double*[6]类型的数组,所以sizeof(**a)=6*sizeof  (double*)=24。***a就表示其中的一个元素,也就是double*了,所以sizeof(***a)=4。至于****a,就是一个double了,所以sizeof(****a)=sizeof(double)=8。


九、分析2个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();     

 }

程序1:

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

程序2:

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

在n比较小的时候,或者对效率不怎么要求的时候,可以用第一种,程序比较简明,而在有些时候,则要用第二种,以提高效率.

 

 

 

十、下面是C中两种if语句判断方式。请问哪种写法更好?为什么? 
   if   (n   ==   10) //   第一种   
   if   (10   ==   n) //   第二种

    用第2种的主要目的是防止写成if(n=10)而导致错误,但现在的编译器一般会给出警告信息所以现在不常用了。有些知名专家他们就推荐用第二种。因为不容易出错。在大软件的团队开发中,一个小小的错误是会有对整个项目有很大影响的,所以应用尽所有的办法来尽力避免一些无畏的错误。虽然你习惯用第一种,但你能保证你每次都不会写少一个等号吗?  改成第二种吧。会省掉很多   debug   的时间的。所以应养成一种比较好的风格。

 

 

附录:

nusigned的存储空间?
under   dos   or   windows  ; 
unsigned   short   的大小为   2   byte,无符号   
under   windows  ; 
int   means   4   byte;

下面的函数实现在一个固定的数上加上一个数,有什么错误,改正? 
int add_n(int n) 

  static int i=100; 
  i+=n; 
  return i; 

    静态局部变量只能赋初值一次,每次调用时不再赋初值,把static去掉就可以了。 

构造函数、析构函数的在基类和派生类中调用顺序?
    对象是由“底层向上”开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数。在对象析构时,其顺序与构造正好相反。

 

写出程序结果: 
void Func(char str[100]) 

  printf("%d/n", sizeof(str)); 
}

    输出是4,这里str被看做一个指针类型。当数组作为参数时,使用sizeof(数组名)数组名字代表的是一个指针类型,注意与以下的区分:
  char str1[10]="123456789";
  printf("%d",sizeof(str1) ; 输出是10

int id[sizeof(unsigned long)]; 这个对吗?为什么??  
  对   这个 sizeof是编译时运算符,编译时就确定了,可以看成和机器有关的常量。

 

输出下面程序结果。 
#include <iostream.h> 
class A 

public: 
virtual void print(void) 

    cout < <"A::print()" < <endl; 

}; 
class B:public A 

public: 
virtual void print(void) 

  cout < <"B::print()" < <endl; 
}; 
}; 
class C:public B 

public: 
virtual void print(void) 

  cout < <"C::print()" < <endl; 

}; 
void print(A a) 

  a.print(); 

void main(void) 

  A a, *pa,*pb,*pc; 
  B b; 
  C c;  
  pa=&a; 
  pb=&b; 
  pc=&c;   
  a.print(); 
  b.print(); 
  c.print();   
  pa->print(); 
  pb->print(); 
  pc->print();  
  print(a); 
  print(b); 
  print(c); 

A::print() 
B::print() 
C::print() 
A::print() 
B::print() 
C::print() 
A::print() 
A::print() 
A::print()

试编写函数判断计算机的字节存储顺序是开序(little endian)还是降序(bigendian) 
 ittle   endian把低字节存放在内存的低位;而big   endian将低字节存放在内存的高位.代码可以上Google 查找

static变量和static 函数各有什么特点? 
    static变量:在程序运行期内一直有效,如果定义在函数外,则在编译单元内可见,如果在函数内,在定义的block内可见; 
    static函数:在编译单元内可见;

请指出下列程序中的错误并且修改 
void GetMemory (char *p)

  p=(char *)malloc(100); 

void Test(void)

  char *str=NULL; 
  GetMemory=(str); 
  strcpy(str,"hello world"); 
  printf(str); 

   str一直都是 NULL;并且运行到strcpy(str, "hello world")将产生错误
这是一道考验你是否真正理解指针的题目,具体讲解可以看下面的链接
修改方法1: 
char *GetMemory()

  char *p=(char *)malloc(100); 
  return p; 

void Test(void){ 
  char *str=NULL; 
  str=GetMemory();
  strcpy(str,"hello world"); 
  printf(str); 
}

方法2:
void GetMemory2(char **p)变为二级指针. 
void GetMemory2(char **p, int num) 

*p = (char *)malloc(sizeof(char) * num); 

void Test(void)

  char *str=NULL; 
  GetMemory=(&str); 
  strcpy(str,"hello world"); 
  printf(str); 
}

 附:

 

不同文件 间使用 extern外部变量(全局变量)/*隐含初始化为0*/
形式1:
一、定义:在一个头文件(c.h)中定义一个extern: extern int x;
  x必须定义且只定义一次。
二、引用: 在另一个文件中引用该extern变量。
先引用该文件:#include "c.h"
再声明引用变量:int x;
形式2:
一、定义:在一个头文件(c.h)中定义一个全局变量: int x;
二、引用:
在其他文件中,只要先声明 extern int x;
就可以使用了

附:
extern  "C"表示编译生成的内部符号名使用C约定 

抱歉!评论已关闭.