面试题(二)

一、选择题

1、 符号链接是一个特殊类型的文件,他的文本属性的第一个字母是l

硬链接:创建硬链接后,文件的索引计数会加1

2、/etc/services 文件定义了网络服务的端口

3、进程类型

针对用户进程,又可以分为交互进程、批处理进程和守护进程三类。 

(1) 交互进程:由一个shell终端启动的进程,在执行过程中,需要与用户进行交互操作,可以运行于前台,也可以运行在后台。 

(2) 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。    

(3) 守护进程:守护进程是一直运行的一种进程,经常在linux系统启动时启动,在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如httpd进程,一直处于运行状态,等待用户的访问。还有经常用的crond进程,这个进程类似与windows的计划任务,可以周期性的执行用户设定的某些任务。

5、kill pid与kill -9 pid的区别

kill pid的作用是向进程号为pid的进程发送SIGTERM(这是kill默认发送的信号),该信号是一个结束进程的信号且可以被应用程序捕获。若应用程序没有捕获并响应该信号的逻辑代码,则该信号的默认动作是kill掉进程。这是终止指定进程的推荐做法。

kill -9 pid则是向进程号为pid的进程发送SIGKILL(该信号的编号为9),从本文上面的说明可知,SIGKILL既不能被应用程序捕获,也不能被阻塞或忽略,其动作是立即结束指定进程。通俗地说,应用程序根本无法“感知”SIGKILL信号,它在完全无准备的情况下,就被收到SIGKILL信号的操作系统给干掉了,显然,在这种“暴力”情况下,应用程序完全没有释放当前占用资源的机会。事实上,SIGKILL信号是直接发给init进程的,它收到该信号后,负责终止pid指定的进程。在某些情况下(如进程已经hang死,无法响应正常信号),就可以使用kill -9来结束进程。

        若通过kill结束的进程是一个创建过子进程的父进程,则其子进程就会成为孤儿进程(Orphan Process),这种情况下,子进程的退出状态就不能再被应用进程捕获(因为作为父进程的应用程序已经不存在了),不过应该不会对整个linux系统产生什么不利影响。

-15 SIGKILL

-9  SIGTERM

 

二、简答题

1、linux 系统调用与库函数的区别?

Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions)。

统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思。面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的api,采用这样的方式有很多种原因,第一:双缓冲技术的实现。第二,可移植性。第三,底层调用本身的一些性能方面的缺陷。第四:让api也可以有了级别和专门的工作面向。

http://blog.csdn.net/qianshanxue11/article/details/52470699

2、 sizeof和strlen的区别?

sizeof计算的是占内存当中的字节数  

strlen计算的是字符串的长度

sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。

strlen只关心存储的数据内容,不关心空间的大小和类型。

http://blog.csdn.net/wuxinliulei/article/details/11178535

sizeof(...)是运算符,不是一个函数。参数可以是数组、指针、类型、对象、函数等。

它的功能是:获得保证能容纳实现所建立的最大对象的字节大小

当参数分别如下时,sizeof返回的值表示的含义如下:

数组——编译时分配的数组空间大小;

指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);

类型——该类型所占的空间大小;

对象——对象的实际占用空间大小;

函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。

    strlen(...)是函数,要在运行时才能计算。

    参数必须是字符型指针(char*), 且必须是以'\0'结尾的。当数组名作为参数传入时,实际上数组就退化成指针了。

   它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0'。返回的长度大小不包括'\0'。

 

3、 C语言分配内存的方式有哪些?C语言中常见的内存错误有哪些?

三种内存分配方式:

  1:从静态存储区分配:全局变量,static变量

  2:从分配:局部变量,函数参数

  3:从分配(动态内存分配):使用malloc或者new操作符(c++)

常见的内存错误:

   1:内存分配未成功

  使用p==NULL来判断是否为空可以避免这个问题或者使用异常处理语句来处理错误。 分配未成功可能是堆内存不够用(内存肯定是够用的,所以这个问题很少出现),最大的可能就是在此malloc之前的malloc分配的内存访问出现了越界

2:分配成功但是没有初始化

 全局变量和静态变量以及数组会自动初始化为0,但是其他类型的数据就是随机系统初始化的,时刻保持一种习惯,创建变量的同时就赋空或者0

 3:内存分配成功,但是操作越界,比如在排序算法循环中,经常没有控制好循环控制变量就很容易出现越界

 4:忘记了释放内存或者释放了部分内存,造成内存泄漏。开始的时候觉得没有什么,当多次出现这个情况就会出现oom

动态分配的内存 malloc和free配对,new delete配对,java中比如各种流打开也要配对关闭,不要太指望gc会自己处理,他只是个机器。

 5:释放了内存却还在继续使用

常见的为函数返回指向“栈内存”的指针或者是引用,它使局部作用的变量,函数结束就会自动释放了

6:释放了内存,但是没有重新滞空,产生野指针!

free只是释放了该指针指向的内存,但是它作为一个独立的变量还是会存在的,不给他赋值他就乱指形成野指针。

7:误以为动态分配的内存会自动释放(很容易忽略!)

  void funTest(){

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

  }

  调用该函数后分配的指针变量p为局部变量会自动释放,但是他指向的内存并不会释放

4、 什么是野指针?如何避免野指针?

野指针:指向内存被释放的内存或者没有访问权限的内存的指针。

“野指针”的成因主要有3种:

(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *p =NULL;

char *str = new char(100);

(2)指针p被free或者delete之后,没有置为NULL。

(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

classA 

{

     public:

voidFunc(void){ cout << “Func of class A” << endl; }

};

 

 

voidTest(void)

{

    A  *p;

    if(...)

    {

A a;

p =&a; // 注意 a 的生命期

    }

    p->Func(); // p是“野指针”

}

如何避免野指针:

一、对指针进行初始化

①将指针初始化为NULL。

char *  p  = NULL;

②用malloc分配内存

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

③用已有合法的可访问的内存地址对指针初始化

char num[30] = {0};

char *p =num;

 

二、指针用完后释放内存,将指针赋NULL

delete(p);

p = NULL;

注:

malloc函数分配完内存后需注意:

①检查是否分配成功(若分配成功,返回内存的首地址;分配不成功,返回NULL。可以通过if语句来判断)

②清空内存中的数据(malloc分配的空间里可能存在垃圾值,用memset或bzero 函数清空内存)

voidbzero(void *s, int n);

 

s是需要置零的空间的起始地址; n是 要置零的数据字节个数。

 

voidmemset(void *start, int value, int size);

 

如果要清空空间的首地址为p,value为值,size为字节数。

http://blog.csdn.net/qq_35212671/article/details/51920851

 

5、 分别写出bool,int,float,指针类型的变量a与“零”的比较语句?

http://blog.csdn.net/Denkensk/article/details/43982773

 

BOOL : if ( !a ) or if(a)  

int : if ( a == 0)  

float : const EXPRESSION EXP = 0.000001  

<span style="white-space:pre">  </span>if ( a < EXP&& a >-EXP)  

pointer :if ( a != NULL) or if(a == NULL) 

 

不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。 

EPSINON应该是一个很小的值吧   因为计算机在处理浮点数的时候是有误差的,所以判断两个浮点数是不是相同,是要判断是不是落在同一个区间的,这个区间就是 [-EPSINON,EPSINON]  EPSINON一般很小,10的-6次方以下吧,具体的好像不确定的,和机器有关。

剖析:

  考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。 

 一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法成“>=”或“<=”形式。如果写成if(x == 0.0),则判为错,得0分。

三、读程序

http://blog.csdn.net/qinning199/article/details/44058727

一、选择题

1、 符号链接是一个特殊类型的文件,他的文本属性的第一个字母是l

硬链接:创建硬链接后,文件的索引计数会加1

2、/etc/services 文件定义了网络服务的端口

3、进程类型

针对用户进程,又可以分为交互进程、批处理进程和守护进程三类。 

(1) 交互进程:由一个shell终端启动的进程,在执行过程中,需要与用户进行交互操作,可以运行于前台,也可以运行在后台。 

(2) 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。    

(3) 守护进程:守护进程是一直运行的一种进程,经常在linux系统启动时启动,在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如httpd进程,一直处于运行状态,等待用户的访问。还有经常用的crond进程,这个进程类似与windows的计划任务,可以周期性的执行用户设定的某些任务。

5、kill pid与kill -9 pid的区别

kill pid的作用是向进程号为pid的进程发送SIGTERM(这是kill默认发送的信号),该信号是一个结束进程的信号且可以被应用程序捕获。若应用程序没有捕获并响应该信号的逻辑代码,则该信号的默认动作是kill掉进程。这是终止指定进程的推荐做法。

kill -9 pid则是向进程号为pid的进程发送SIGKILL(该信号的编号为9),从本文上面的说明可知,SIGKILL既不能被应用程序捕获,也不能被阻塞或忽略,其动作是立即结束指定进程。通俗地说,应用程序根本无法“感知”SIGKILL信号,它在完全无准备的情况下,就被收到SIGKILL信号的操作系统给干掉了,显然,在这种“暴力”情况下,应用程序完全没有释放当前占用资源的机会。事实上,SIGKILL信号是直接发给init进程的,它收到该信号后,负责终止pid指定的进程。在某些情况下(如进程已经hang死,无法响应正常信号),就可以使用kill -9来结束进程。

        若通过kill结束的进程是一个创建过子进程的父进程,则其子进程就会成为孤儿进程(Orphan Process),这种情况下,子进程的退出状态就不能再被应用进程捕获(因为作为父进程的应用程序已经不存在了),不过应该不会对整个linux系统产生什么不利影响。

-15 SIGKILL

-9  SIGTERM

 

二、简答题

1、linux 系统调用与库函数的区别?

Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions)。

统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思。面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的api,采用这样的方式有很多种原因,第一:双缓冲技术的实现。第二,可移植性。第三,底层调用本身的一些性能方面的缺陷。第四:让api也可以有了级别和专门的工作面向。

http://blog.csdn.net/qianshanxue11/article/details/52470699

2、 sizeof和strlen的区别?

sizeof计算的是占内存当中的字节数  

strlen计算的是字符串的长度

sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。

strlen只关心存储的数据内容,不关心空间的大小和类型。

http://blog.csdn.net/wuxinliulei/article/details/11178535

sizeof(...)是运算符,不是一个函数。参数可以是数组、指针、类型、对象、函数等。

它的功能是:获得保证能容纳实现所建立的最大对象的字节大小

当参数分别如下时,sizeof返回的值表示的含义如下:

数组——编译时分配的数组空间大小;

指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);

类型——该类型所占的空间大小;

对象——对象的实际占用空间大小;

函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。

    strlen(...)是函数,要在运行时才能计算。

    参数必须是字符型指针(char*), 且必须是以'\0'结尾的。当数组名作为参数传入时,实际上数组就退化成指针了。

   它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0'。返回的长度大小不包括'\0'。

 

3、 C语言分配内存的方式有哪些?C语言中常见的内存错误有哪些?

三种内存分配方式:

  1:从静态存储区分配:全局变量,static变量

  2:从分配:局部变量,函数参数

  3:从分配(动态内存分配):使用malloc或者new操作符(c++)

常见的内存错误:

   1:内存分配未成功

  使用p==NULL来判断是否为空可以避免这个问题或者使用异常处理语句来处理错误。 分配未成功可能是堆内存不够用(内存肯定是够用的,所以这个问题很少出现),最大的可能就是在此malloc之前的malloc分配的内存访问出现了越界

2:分配成功但是没有初始化

 全局变量和静态变量以及数组会自动初始化为0,但是其他类型的数据就是随机系统初始化的,时刻保持一种习惯,创建变量的同时就赋空或者0

 3:内存分配成功,但是操作越界,比如在排序算法循环中,经常没有控制好循环控制变量就很容易出现越界

 4:忘记了释放内存或者释放了部分内存,造成内存泄漏。开始的时候觉得没有什么,当多次出现这个情况就会出现oom

动态分配的内存 malloc和free配对,new delete配对,java中比如各种流打开也要配对关闭,不要太指望gc会自己处理,他只是个机器。

 5:释放了内存却还在继续使用

常见的为函数返回指向“栈内存”的指针或者是引用,它使局部作用的变量,函数结束就会自动释放了

6:释放了内存,但是没有重新滞空,产生野指针!

free只是释放了该指针指向的内存,但是它作为一个独立的变量还是会存在的,不给他赋值他就乱指形成野指针。

7:误以为动态分配的内存会自动释放(很容易忽略!)

  void funTest(){

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

  }

  调用该函数后分配的指针变量p为局部变量会自动释放,但是他指向的内存并不会释放

4、 什么是野指针?如何避免野指针?

野指针:指向内存被释放的内存或者没有访问权限的内存的指针。

“野指针”的成因主要有3种:

(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *p =NULL;

char *str = new char(100);

(2)指针p被free或者delete之后,没有置为NULL。

(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

classA 

{

     public:

voidFunc(void){ cout << “Func of class A” << endl; }

};

 

 

voidTest(void)

{

    A  *p;

    if(...)

    {

A a;

p =&a; // 注意 a 的生命期

    }

    p->Func(); // p是“野指针”

}

如何避免野指针:

一、对指针进行初始化

①将指针初始化为NULL。

char *  p  = NULL;

②用malloc分配内存

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

③用已有合法的可访问的内存地址对指针初始化

char num[30] = {0};

char *p =num;

 

二、指针用完后释放内存,将指针赋NULL

delete(p);

p = NULL;

注:

malloc函数分配完内存后需注意:

①检查是否分配成功(若分配成功,返回内存的首地址;分配不成功,返回NULL。可以通过if语句来判断)

②清空内存中的数据(malloc分配的空间里可能存在垃圾值,用memset或bzero 函数清空内存)

voidbzero(void *s, int n);

 

s是需要置零的空间的起始地址; n是 要置零的数据字节个数。

 

voidmemset(void *start, int value, int size);

 

如果要清空空间的首地址为p,value为值,size为字节数。

http://blog.csdn.net/qq_35212671/article/details/51920851

 

5、 分别写出bool,int,float,指针类型的变量a与“零”的比较语句?

http://blog.csdn.net/Denkensk/article/details/43982773

 

BOOL : if ( !a ) or if(a)  

int : if ( a == 0)  

float : const EXPRESSION EXP = 0.000001  

<span style="white-space:pre">  </span>if ( a < EXP&& a >-EXP)  

pointer :if ( a != NULL) or if(a == NULL) 

 

不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。 

EPSINON应该是一个很小的值吧   因为计算机在处理浮点数的时候是有误差的,所以判断两个浮点数是不是相同,是要判断是不是落在同一个区间的,这个区间就是 [-EPSINON,EPSINON]  EPSINON一般很小,10的-6次方以下吧,具体的好像不确定的,和机器有关。

剖析:

  考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。 

 一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法成“>=”或“<=”形式。如果写成if(x == 0.0),则判为错,得0分。

三、读程序

http://blog.csdn.net/qinning199/article/details/44058727

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值