题目出处:IT公司面试手册 点击打开链接
一,简答题(30分)
1,当前计算机系统一般会采用层次结构存储数据,请介绍下典型计算机存储系统一般分为哪几个层次,为什么采用分层存储数据能有效提高程序的执行效率?(10分)
Ps:这题是坚决打了博主一个巴掌。捂个脸先,谁叫我这学期没好好学计算机组成原理这门课,老师的苦心就是这样被我们浪费的。。我蹲个墙角先。
目前,在计算机系统中通常采用三级层次结构来构成存储系统,主要由高速缓冲存储器Cache、主存储器和辅助存储器组成。存储系统多级层次结构中,由上向下分三级,其容量逐渐增大,速度逐级降低,成本则逐次减少。整个结构又可以看成两个层次:它们分别是cache一主存层次和主存一辅存层次。这个层次系统中的每一种存储器都不再是孤立的存储器,而是一个有机的整体。它们在辅助硬件和计算机操作系统的管理下,可把主存一辅存层次作为一个存储整体,形成的可寻址存储空间比主存储器空间大得多。由于辅存容量大,价格低,使得存储系统的整体平均价格降低。由于Cache的存取速度可以和CPU的工作速度相媲美,故cache一主存层次可以缩小主存和CPU之间的速度差距,从整体上提高存储器系统的存取速度。尽管Cache成本高,但由于容量较小,故不会使存储系统的整体价格增加很多。
简而言之:高速缓存解决了存储系统的速度问题,辅助存储器则解决了存储系统的容量问题。采用多级层次结构的存储器系统可以有效的解决存储器的速度、容量和价格之间的矛盾。
2,Unix/Linux系统中僵尸进程是如何产生的?有什么危害?如何避免?(10分)
僵尸进程:在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。
僵尸进程的危害
由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束. 那么不会因为父进程太忙来不及wait子进程,或者说不知道子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会.因为UNIX提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到. 这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等. 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPUtime taken by the process等), 直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果你进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免.
僵尸进程的避免
1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起
2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收
3.如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号
4. 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。
参考资料:百度百科—僵尸进程
僵尸进程的危害与避免:点击打开链接
3,简述Unix/Linux系统中使用socket库编写服务器端程序的流程,请分别用对应的socket通信函数表示(10分)
TCP socket通信
服务器端流程如下:
1.创建serverSocket
2.初始化serverAddr(服务器地址)
3.将socket和serverAddr绑定 bind
4.开始监听 listen
5.进入while循环,不断的accept接入的客户端socket,进行读写操作write和read
6.关闭serverSocket
客户端流程:
1.创建clientSocket
2.初始化serverAddr
3.链接到服务器 connect
4.利用write和read 进行读写操作
5.关闭clientSocket
出处:http://gaomei2008.blog.163.com/blog/static/1852480520139863929680/
博主对unix/linux是一点都不懂啊,哎。
二,算法与程序设计题
1,使用C/C++编写函数,实现字符串反转,要求不使用任何系统函数,且时间复杂度最小,
函数原型:char*reverse_str(char* str)。(15分)
/*
环境win8,vs2012
时间:2014-6-28
by:不吃青瓜
*/
#include<stdio.h>
char* reverse_str(char* str)
{
if(str==NULL)
return NULL;
char temp;
int i,j;
//不能使用库函数,只能遍历一遍了
for(i=0; *(str+i)!='\0'; ++i){ /*故意为空*/ };
j=i-1; //本来这句话也可以写在for里面,不过这有可能会引起理解困难
for( i=0; i<j ; --j,++i)
{
temp=*(str+i);
*(str+i)=*(str+j);
*(str+j)=temp;
}
return str;
}
int main()
{
char str[]="abcdef";
printf("%s\n",reverse_str( str ));
getchar();
return 0;
}
2,给定一个如下格式的字符串(1,(2,3),(4,(5,6),7))括号内的元素可以是数字,也可以是另一个括号,请实现一个算法消除嵌套的括号,比如把上面的表达式变成:(1,2,3,4,5,6,7),如果表达式有误请报错。(15分)
/*
环境win8,vs2012
时间:2014-6-28
by:不吃青瓜
*/
#include<stdio.h>
#include<string.h>
//这题我不太明白这个题目的意思是要原字符串上直接修改,
//还是要存在子字符串上,我实现的是直接在原字符串上修改,如果需要子串,直接创建一个子指针进行赋值就可以了
int clean_str(char *source_str)
{
if(source_str==NULL)
{
printf("字符串不存在\n");
return -1;
}
int length=strlen(source_str);
int i=0;
int sub_i=0;
int bracket_count=0;//记录括号
int num_count=0;//数字的数量
int dot_count=0;//逗号的数量
//判断括号的方向以及数量是否正确
for( i=0; i<length;i++)
{
if(*(source_str+i)=='(')
bracket_count++;
else if(*(source_str+i)==')')
bracket_count--;
else if(*(source_str+i)==',')
dot_count++;
else if(*(source_str+i)<='9' && *(source_str+i)>='0' )
num_count++;
else
{
printf("出现未知符号\n");
return -1;
}
//在循环体里判断的原因是为了防止出现 ")(" 这种情况
if(bracket_count<0)
{
printf("'('数量出现错误\n");
return -1;
}
}
if(bracket_count>0)
{
printf(" ')'数量出现错误\n");
return -1;
}
//逗号永远会比数字少一个,除非没有数字当然也就没有逗号
if(num_count==0 && dot_count==0)
{
//空
}
else if(dot_count!=num_count-1)
{
printf("','号数量出现错误\n");
return -1;
}
//现在还需要判断的条件是 "," 的前面不可以是 '(',后面不可以是 ')'
for( i=0; i<length;++i)
{
//第一个元素
if(i==0 && *source_str!='(')
{
printf("第一个元素不是'('\n");
return -1;
}
else if(i==0 && *source_str=='(')
{
*(source_str+sub_i++)=*(source_str+i);
continue;
}
//最后一个元素
if( i==length-1 && *(source_str+i)!=')')
{
printf("最后一个字符不是')'\n");
return -1;
}
else if( i==length-1 && *(source_str+i)==')')
{
*(source_str+sub_i++)=*(source_str+i);
continue;
}
//其它情况
//'('不能跟','
if( *(source_str+i)=='(')
{
if( *(source_str+i+i)==',' )
{
printf("'('后面字符出错");
return -1;
}
else
{
continue;
}
}
//‘)’后面只能是‘)’或者‘,’
else if( *(source_str+i)==')')
{
if( *(source_str+i+1)==')' || *(source_str+i+1)==',' )
{
continue;
}
else
{
printf("')'后面出现错误");
return -1;
}
}
//逗号后面必须是数字,或者'('
else if( *(source_str+i)==',')
{
if(*(source_str+i+1)==')')
{
printf("','后面字符出错");
return -1;
}
*(source_str+sub_i++)=*(source_str+i);
}
else
*(source_str+sub_i++)=*(source_str+i);
}//for
*(source_str+sub_i)='\0';
printf("%s\n",source_str);
return -1;
}
int main()
{
char str1[]="(1,(2,3),(4,(5,6),7))";
char str2[]="((1))";
//这种方式虽然说括号冗余了,但按照题目来说,
//括号里可以是括号和数字,因此不算格式错误
char str3[]="(1,,2)";//错,逗号相连
char str4[]="(())"; //像这个的话,按我的理解去掉里面括号就可以了,
char str5[]="()()"; //这个不算括号嵌套
clean_str(str1);
clean_str(str2);
clean_str(str3);
clean_str(str4);
clean_str(str5);
getchar();
return 0;
}
由于博主水平有限,如有错误还望各位道友指正。