练习一
1.下面程序的输出是什么?
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
解析:正确答案是第二个,即2,5
首先看*(a + 1)
,这个就是a[1],很容易。比较不常见的是(&a + 1)
我们知道a就已经算是一个地址了。这个地址代表的事这个数组的第一个元素的地址。而&a就代表数组的地址。(&a + 1)
相当于偏移了一个数组。然后得到地址给ptr,如下图:
然后*(ptr - 1)
是表示那个指针向前移动了一个整形,然后就指向了5.所以结果就是2,5啦。
2.有下面一段代码:
char szMsisdn[MAX_LEN_MSISDN-1];
szMsisdn[sizeof(szMsidn)]=’\0’;
则对执行以上代码后,会出现什么问题?
解析:答案是选择第二个,数组越界。
首先先复习一下sizeof
运算符,sizeof
返回一个表达式或者一个类型名字所占的字节数。运算符满足右结合率,其所得的值是一个size_t
类型的常量表达式。sizeof
一般有两种使用方式。
sizeof(类型)
sizeof 表达式
a在第二种形式中,sizeof返回的是表达式结果类型的大小。(sizeof并不实际计算其运算对象的值)这里举一个例子来看看sizeof的一些性质。
#include <iostream>
int main()
{
std::cout<<"Basic Type:"<<std::endl;
std::cout<<"int:"<<sizeof(int)<<std::endl;
std::cout<<"short:"<<sizeof(short)<<std::endl;
std::cout<<"long:"<<sizeof(long)<<std::endl;
std::cout<<"float:"<<sizeof(float)<<std::endl;
std::cout<<"double:"<<sizeof(double)<<std::endl<<std::endl;
int a,*p;
int c[10];
std::cout<<"expression test:"<<std::endl;
std::cout<<"sizeof a: "<<sizeof a<<std::endl; //the size of type of a;equal to sizeof(int)
std::cout<<"sizeof p: "<<sizeof p<<std::endl; //the size of pointer
std::cout<<"sizeof *p: "<<sizeof *p<<std::endl; //the type of p point to...equal to sizeof(int)
std::cout<<"sizeof c: "<<sizeof c<<std::endl; //the whole size of array
std::cout<<"sizeof *c: "<<sizeof *c<<std::endl;
char s[10];
std::cout<<"sizeof s: "<<sizeof s<<std::endl;
std::cout<<"sizeof *s: "<<sizeof *s<<std::endl;
return 0;
}
x这里回到题目,
char szMsisdn[MAX_LEN_MSISDN-1];
这句话就是说明建立了一个长度为MAX_LEN_MSISDN-1的数组,那么这个数组的索引是0~MAX_LEN_MSISDN-2,
szMsisdn[sizeof(szMsidn)]=’\0’;
这句话说明了他是在索引MAX_LEN_MSISDN-1的地方赋值,因为对于char数组sizeof返回的字节数和数组中的元素个数是一样的(其他的类型都不一定会是这个样子)。这就是很明显的数组越界了。
3.某函数申明如下:
void Func(int &nVal1);
有int a,下面使用正确的为:
选择第一个。
就是引用的基本使用,很简单。
4.在x86系统下,sizeof如下结构体的值是多少?
struct{
char a[10];
int b;
short c[3];
}
正确答案是24
偏移量必须为其类型的整数倍,结构体大小必须是所有成员大小的整数倍
char 偏移量0,地址0-9
int 偏移量10不是sizeof(int)的倍数,故而修正为12,地址12-15
short 偏移量16,地址16-21
结构题大小22不是1,2,4的公倍数,故而vc自动补充2个数为24
5.设x、y、t均为int型变量,则执行语句:t=3; x=y=2; t=x++||++y; 后,变量t和y的值分别为__
这里正确答案为A,t=1,y=2
x++||++y执行后的结果是真,即1,然后赋值给t。因为是或运算,所以在判断x++时真后,后面的++y就不再执行了,所以y值没有变还是2.(这道题的考点是运算优先级和判断运算符的性质)
6.在32位机器中,如下代码:
void example(char acWelcome[]){
printf("%d",sizeof(acWelcome));
return;
}
void main(){
char acWelcome[]="Welcome to Huawei Test";
example(acWelcome);
return;
}
的输出是?
这道题的答案是4
这里就要联想到上面第2题的对于sizeof的补充知识了,因为在那个函数里面sizeof是对于一个指针来sizeof的,因此这里就是指针占的字节,在32位中指针是4个字节,因此答案就是4.假如是64位的,那么答案就是8.
7.以下描述正确的是?
正确答案是c
对于A的话参看 http://blog.csdn.net/zy1691/article/details/3606128
《Effective C++》的第33款:
即使是最简单的虚函数调用,编译器的内联处理程序对它也爱莫能助。(这一点也不奇怪。virtual的意思是”等到运行时再决定调用哪个函数”,inline的意思是”在编译期间将调用之处用被调函数来代替”,如果编译器甚至还不知道哪个函数将被调用,当然就不能责怪它拒绝生成内联调用了)。
B 会冲突,实例调用的时候不知道调用哪个了。。
C A* a = new B //B是A的子类
delete a
此时父类析构函数需要加virtual,如果不加virtual,那么最后只会调用A的析构函 数,而派生的部分,并没有得到析构,导致内存泄露。
B* b = new B
delete b
此时父类析构函数并不需要加virtual,就是一个很正常的构造析构过程
A() -> B() -> ~B() -> ~A()
8.下列定义语句中,错误的是
答案选择A,
int *p[4]; //指针数组。 是个有4个元素的数组, 每个元素的是指向整型的指针 。(数组的每个元素都是指针)
int (*p)[4]; //数组指针。 它是一个指针,指向有4个整型元素的数组。 (一个指针指向有4个整型元素的数组)
int func(void); //指针函数。 无参函数, 返回整型指针。 (函数的返回值为int)
int (*func)(void); //表示函数指针,可以指向无参, 且返回值为整型指针的函数。 (函数的返回值为int)
9.字符串”qiniu”根据顺序不同有多少种排列组合的方式?
由于有两个i,可以看成是有5个位置,只要确定了q,n,u的位置,字符串就确定了,因此,是5×4×3=60
10.设串长为n,模式串长为m,则KMP算法所需的附加空间__。
BF算法(普通匹配算法):时间复杂度O(m*n);空间复杂度O(1)
KMP算法:时间复杂度O(m+n);空间复杂度O(n)
11.某字符串满足:concat(head(s),head(tail(tail(s))))="ac",
(head,tail的定义同广义表),则S=()
概念解释:广义表L=(A,B,C),表头是A,表尾是(B,C),这是定义。
tail()表示取字符串的尾部,head()表示取字符串的头,concat()表示字符串拼接。
取两次尾部一次头部,然后合并,答案是C。