部分真题整理2

来源:互联网 发布:二叉树层次打印 java 编辑:程序博客网 时间:2024/05/22 11:34
1、声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是(C)
(int *p[10])(int*)int [10]*p(int *)int (*(*p)[10])(int *)int ((int *)[10])*p
以上选项都不正确
解析:
int (*(*func)[5])(int *p);
func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。
详见:http://blog.csdn.net/u011385799/article/details/47783555


2、 一个进程从执行状态转换到阻塞状态的可能原因是本进程(BD)。
时间片完
需要等待其他进程的执行结果
执行了V操作
执行了P操作
解析:
运行态:进程占用CPU,并在CPU上运行;
就绪态:进程已经具备运行条件,但是CPU还没有分配过来;
阻塞态:进程因等待某件事发生而暂时不能运行; 进程在一生中,都处于上述3中状态之一。
运行---》就绪: 时间片用完。
就绪---》运行:运行的进程的时间片用完,调度就转到就绪队列中选择合适的进程分配CPU
运行---》阻塞:发生了I/O请求或等待某件事的发生
阻塞---》就绪:进程所等待的事件发生,就进入就绪队列
P操作是阻塞作用
V操作是唤醒作用


3、已知如下代码,并在两个线程中同时执行f1和f2,待两个函数都返回后,a的所有可能值是哪些?(ABCD)

 int a = 2, b = 0, c = 0;void f1() { b = a * 2; a = b; }void f2(){c = a + 11;a = c;}
4
13
15
26

解析:

考虑四行代码的执行顺序即可
(1)b=a*2,c=a+11,a=c,a=b a=4
(2)b=a*2,c=a+11,a=b,a=c a=13
(3)b=a*2,a=b,c=a+11,a=c a=15
(4)c=a+11,a=c,b=a*2,a=b a=26


4、以下程序段的输出结果是(A)
char s[]="\\123456\123456\t";printf("%d\n",strlen(s));
12
13
16
以上都不对
解析:
char s[] = "//123456/123456/t";
这样strlen(s)输出17.
char s[] = "\\123456\123456\t";
这样strlen(s)输出12.
计算字符串长度时关键是要注意辨认转义字符;
含转义字符的有:
\\ 表示字符 \
\123表示字符 {
\t 表示制表符
这些都是一个字符。


5、如下程序
 #include <iostream>using namespace std;class A{public:A(){printf("A");}};int main(){A *p1 = new A;A *p2 = (A *)malloc(sizeof(A));return 0;}
该程序运行结果为(A)
A
AA
崩溃
不可预测
解析:
1 A *p1 = new A;
上面这条语句会创建一个A对象,输出一个A;

1 A *p2 = (A *)malloc(sizeof(A));
sozeof(A)为1,这条语句创建一个大小为1的A的指针数组,但是没有创建任何A对象,因此不输出A
这题主要是考的new和malloc的区别,new会分配内存,并调用类的构造函数创建对象,而malloc只是分配内存,不调用类的构造函数创建对象,这个程序应该用delete p1;显示释放掉p1所指的堆上的内存,这样才会调用类的析构函数,否则不会调用。


6、设有以下宏定义:
#define N 3#define Y(n)((N+1)*n)
则执行语句:z=2*(N+Y(5+1));后,z的值为:(C)
38
42
48
54
解析:
#define N 3
#define Y(n)((N+1)*n)//【注意此处n没有加括号】,所以后面的n并不是(5+1)
z=2*(N+Y(5+1)) =2*(N+(N+1)*5+1)=2*(3+4*5+1)=48


7、 以下描述正确的是?(C)
虚函数是可以内联的,可以减少函数调用的开销提高效率
类里面可以同时存在函数名和参数都一样的虚函数和静态函数
父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
以上都不对
解析:
delete子类对象是一定会调用父类的析构函数的先调用子类的析构函数然后调用父类的析构函数;如果要调用父类指向子类的对象,此时才需要父类的析构函数是虚的。


8、下列运算符中,在C++语言中不能重载的是:(C)
*
>=
::
delete
解析:
在C++中,sizeof运算符,.成员运算符,.*成员指针运算符,::作用域解析运算符以及?:条件运算符不能被重载


9、说明一下++p 与 p++ 的区别。(B)
没有区别
++p更好一些
p++更好一些
和编译器有关
解析:
假设这样的一个例子:
 int p = -1;int y = 0;y = p++ + ++P;
先分析一下它的汇编代码(没有优化):
 subl $40, %esp ; 分配40字节 movl $1, -16(%ebp) ; 存储 p movl $0, -12(%ebp) ; 存储 y movl -16(%ebp), %eax ; 这3步执行 p++ leal 1(%eax), %edx movl %edx, -16(%ebp) addl $1, -16(%ebp) ; 这2步执行 ++p movl -16(%ebp), %edx addl %eax, %edx ; 相加操作 movl %edx, -12(%ebp) ; 结果写回 y 
可以看出p++需要3步,++p需要2步,而且修改p的值是不一样的,看出++p的效率比p++的高。
前++返回对象的引用,效率较高,故选择++p


10、下面有关final, finally, finalize的区别描述错误的是?(B)
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承
如果一个方法被声明为final,可以被覆盖
finally在异常处理时提供 finally 块来执行任何清除操作。
Java使用 finalize() 方法在垃圾收集器象从内存中清除出去之前做必要的清理工作
解析:
final关键字可用于修饰类、变量和方法。final修饰的类不能被继承,final修饰的方法不能被重写,final修饰的变量不可被修改,一旦获得初始值,该变量就不能被重新赋值。


11、 以下选项中函数形参不是指针的是?(C)
fun( int ﹡a ){…}
fun( int a [ 10 ] ) {…}
fun( int &p ) {…}
fun( int p[ ]) {…}
解析:
B选项和D选项是将数组作为函数参数;A选项是将指针作为函数参数;
C. 这个& 是引用,不是取地址.


12、下面程序应该输出多少?(A)
 char *c[] = { "ENTER", "NEW", "POINT", "FIRST" }; char **cp[] = { c+3, c+2, c+1, c }; char ***cpp = cp; int main(void){ printf("%s", **++cpp); printf("%s", *--*++cpp+3); printf("%s", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); return 0;}
POINTERSTEW
FERSTEPOINW
NEWPOINTW
POINTFIREST
解析:
这个主要是执行顺序的问题,我加了一下括号:
printf("%s\n", **(++cpp));
printf("%s\n", (*(--(*(++cpp)))) + 3);
printf("%s\n", *(cpp[-2]) + 3);
printf("%s\n", cpp[-1][-1] + 1);
其中考了指针应用,隐含中也考了运算符优先级的问题(*--*++cpp+3)
c是一个指针数组,每个数组单元都是一个指针,指向一个字符创。
即c[0]="ENTER"......c[3]="FIRST"
由于[]与*运算本质几乎是一致的,以下用[]替换*更容易理解。
c[i]=*(c+i)
c和c+i都是char*[]类型,它可以退化成char**类型,它正好是一个char**数组
cp[0]=c+3 .....cp[3]=c
引用后cp[0][0]=*(c+3)=c[3]="FIRST"
cp是char**[]类型,它可以退化成char***类型,正好与cpp类型一致。
1>++ccp的值是cp+1 *++p=*(cp+1)=cp[1] **++p=*(cp[1])=c[2]="POINT"
2>运算符优先级决定运算先后关系
++ccp的值是cp+2 *++p=*(cp+2)=cp[2]=c+1 --*++p=c *--*++p=*(c+0)=c[0]="ENTER"再+3字符串指向"ER"
3>cpp的值为cp+2 cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3再引用*(c+3)=c[3]="FIRST"字符串指到"ST"
4>cpp的值没变,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2再[-1]得*(c+2-1)=c[1]="NEW",+1字符创指针指到"EW"
翻来覆去,记得这个换算关系式即可,c[i]=*(c+i)。


13、 有如下程序段:
 void GetMemeory(char* p){p = (char*) malloc (100);}void test(){char *str=NULL;GetMemory(str);strcpy(str,”Thunder”);strcat(str+2, “Downloader”);//*(str+2)=u;把Downloader连接到str+2的串尾后printf(str);}
请问运行Test函数结果是:(D)
Thunder Downloader
under Downloader
Thunderownloader
程序崩溃
解析:
在函数中给指针分配空间,实际上是给指针的临时变量分配空间,函数结束后,这个临时变量也消亡,而str仍然为NULL,没有为其分配空间,此时strcpy()是肯定会出错的。
若改为void GetMemeory(char* &p);则能正常运行得到结果 ThunderDownloader


14、在c++中,
const int i = 0; int *j = (int *) &i; *j = 1; printf("%d,%d", i, *j)
输出是多少?(A)
0,1
1,1
1,0
0,0
解析:
这个题一定要注意是在C++中的运行结果。
在C语言中
void main(){const int i = 0;int *j = (int *)&i;*j = 1;printf("%d,%d", i, *j);system("pause");}
结果输出为1,1
在C++中
 #include<iostream>using namespace std;int main(void){const int i=0;int *j = (int *)&i;*j = 1;printf("%d,%d", i, *j);system("pause");return 0;}
结果输出为0,1
分析:C语言中的const是运行时const,编译时只是定义,在运行才会初始化。C语言中const变量不能用于成为数组长度等作为编译时常量的情况,原因就在此。C语言const变量在运行时改变了是可以再次读出改变后的值的。
C++中,const变量是编译时的常量,可以向#define定义的常量一样使用。故C++中const变量的值在编译时就已经确定了,直接对cosnt变量进行了值的替换,因此当const变量的值改变时,const的变量值是不会得到更新的。
这几行代码在C和C++中都会改变const变量的值,只不过C++中const变量在编译的时候已经确定了,而C中的const变量可以在运行时改变后再次读取。以下代码核实了C++中的const变量确实被改变了。
#include<stdio.h>#include<iostream>using namespace std;int main(void){const int i=0;int *j = (int *)&i;*j = 1;printf("%d,%d\n", i, *j);cout << "i address"<<&i << endl;cout << "j address"<<j << endl;return 0;}
同一个地址,即同一个变量。C++中const变量确实别改变了。i的值没有更新而已。
这跟编译器的优化编译有关。
C++中的常量折叠:指const变量(即常量)值 放在编译器的符号表中 ,计算时编译器直接从表中取值,省去了访问内存的时间,从而达到了优化。
printf("%d,%d", i, *j), 因为i是const的,第一个输出值在编译期间就已经被替换成0了,局部const变量放在栈区,虽不能直接修改但可以通过指针间接修改,
还要注意这是局部的const,全局的就不能修改了


15、在x86的机器上,int a=0xabcd1234 char b=((char*)&a)[0]请问b是多少(D)
0xa
0x4
0xab
0x34
解析:
x86是小端存储,即高位存储在高地址,低位存储在低地址。
int a = 0xabcd1234;
内存中 ab cd 12 34,b作为一个char指针指向的地址为0x34.
高 --> 低


16、12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?(B)
120
132
145
153
解析:
C(12,6)-C(12,5)=132
卡特兰数问题,这是我在牛客网答题遇到的第三个卡特兰数问题了,前两个分别是50美分1美元那个排队买票问题和6对括号的组合问题。解释起来有点麻烦,下面慢慢解释吧:
我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排.
用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有6个0,6个1的序列,就对应一种方案.
比如010101010101就对应着
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
问题转换为,这样的满足条件的01序列有多少个.
观察1的出现,显然,在这个1之前出现的那些0,1对应的人要么是在这个1左边,要么是在这个1前面.而且肯定要有一个0在这个1前面,也就是要求,0的个数不小于1的个数.
假设我们不考虑这个限制条件,那么全部的01排列共有C(2n,n)种,也就是一半0一半1的情况
现在我们要把其中不符合要求的数量去掉
在任何不符合条件的序列中,找出使得1的个数超过0的个数的第一个1的位置,然后在导致并包括这个1的部分序列中,以1代替所有的0并以0代表所有的1。结果总的序列变成一个有(n+1)个0和(n-1)个1的序列。而且这个过程是可逆的,也就是说任何一个有(n+1)个0和(n-1)个1构成的序列都能反推出一个不符合条件的序列,所以不符合条件的序列个数为C(2n,n-1)
所以最终结果就是C(2n,n)-C(2n,n-1)
本题中2n=12
0 0
原创粉丝点击