c++ 容易出错的笔试题
来源:互联网 发布:liguo矩阵怎么使用 编辑:程序博客网 时间:2024/06/13 03:40
这是一个关于析构函数和构造函数运行顺序
class B{public:B(){cout<<"default constructor"<<endl;}~B(){cout<<"destructed"<<endl;}B(int i):data(i) //B(int) works as a converter ( int ->instance of B){cout<<"constructed by parameter "<< data <<endl;}private:int data;};B Play( B b) {return b ;}
int main(int argc, char* argv[]){B t1 = Play(5); B t2 = Play(t1);return 0;}
show:
为什么会多了2行 也就是为什么会多掉用2次析构函数
答案:
其实就是在return 之后函数会把函数内部的局部变量全部释放,当然还有全局函数中的临时变量,被调用了2次。
2:
如下函数,在32 bit系统foo(2^31-3)的值是:
int foo(int x) { return x&-x; }
A:0 B: 1 C: 2 D: 4
答案为:C解答:
1:foo(x)里面的答案为26 (这里不做解释了)
2:函数中的return x& -x; 为了方便理解改为: x& (-x)
3:值代入为: 26 & (-26)
4:变为二进制为: 0010 0110 (26) & 1101 1010(-26)
注意: 在计算机中负数都是以补码的方式: 所以 -26 的反码为 1101 1001,然后加 1 为补码:1101 1010
5:结果为 2
3:
unsigned char i=0x80;
printf("0x%x\n", ~i>>3+1);
结果很简单为: 0x7;
解释:
1: + 号的优先级大于 >>
2:表达式变为: ~i >>(3+1)
3:求解1: 0x7f >> 4;
4:求解2: 127 / 16 = 7;
4: 静态对象是否调用构造函数?
#include <iostream> using namespace std; class A { public: A() { cout << "A's Constructor Called " << endl; } }; class B { static A a; public: B() { cout << "B's Constructor Called " << endl; } }; int main() { B b; return 0; }
输出:
B's Constructor Called
解释:上面的程序只是调用了B的构造函数,没有调用A的构造函数。因为静态成员变量只是在类中声明,没有定义。静态成员变量必须在类外使用作用域标识符显式定义。
如果我们没有显式定义静态成员变量a,就试图访问它,编译会出错,比如下面的程序编译出错:
#include <iostream> using namespace std; class A { int x; public: A() { cout << "A's constructor called " << endl; } }; class B { static A a; public: B() { cout << "B's constructor called " << endl; } static A getA() { return a; } }; int main() { B b; A a = b.getA(); return 0; }
输出:
Compiler Error: undefined reference to `B::a
如果我们加上a的定义,那么上面的程序可以正常运行,
注意:如果A是个空类,没有数据成员x,则就算B中的a未定义也还是能运行成功的,即可以访问A。
#include <iostream> using namespace std; class A { int x; public: A() { cout << "A's constructor called " << endl; } }; class B { static A a; public: B() { cout << "B's constructor called " << endl; } static A getA() { return a; } }; A B::a; // definition of a
//<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">在类中的静态成员变量使用中需要注意的是,如果代码中使用了这个静态成员变量,则改静态成员变量必须要有类外的一次声明,形式如下:</span><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px;">//VariableType ClassType::Variable;</p> int main() { B b1, b2, b3; A a = b1.getA(); return 0; }
输出:
A's constructor called
B's constructor called
B's constructor called
B's constructor called
上面的程序调用B的构造函数3次,但是只调用A的构造函数一次,因为静态成员变量被所有对象共享,这也是它被称为类变量的原因。同时,静态成员变量也可以通过类名直接访问,比如下面的程序没有通过任何类对象访问,只是通过类访问a。
int main() { // static member 'a' is accessed without any object of B A a = B::getA(); return 0; }
输出:
A's constructor called
5: 下面代码会报错吗?为什么?
class A {public: int m; void print() { cout << "A\n"; } };A *pa = 0;pa->print();
答案:正常输出。上面的代码可以这样理解(这非常重要):
void print(A *this) { cout << "A\n"; } A *pa = 0;print_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; }
解答:
c是一个指针数组,每个数组元素都是char*类型的指针,值分别是那些字符串(的首地址):
c[0] = "ENTER"
c[1] = "NEW"
c[2] = "POINT"
c[3] = "FIRST"
而[]和*是本质一样的运算,即c[i]=*(c+i)。
c和c+i都是char *[]类型,它可以退化成char **类型,再看cp,它正好是一个char **的数组,来看它的值:
cp[0] = c + 3
cp[1] = c + 2
cp[2] = c + 1
cp[3] = c
引用后就有:cp[0][0]=*(c + 3)=c[3]="FIRST",以此类推。
cp是char **[]类型,它可以退化成char ***类型,看最后的cpp,它正是char ***类型,它是一个指针变量,和上面两个不同,上面两个是数组。
这样分析过后,下面的解析就一目了然了:
- printf("%s",**++cpp);
++cpp的值是cp+1,引用一次后是cp[1]再引用是*cp[1]=c[2]="POINT",第一句的输出 - printf("%s",*--*++cpp+3);
再++cpp的值是cp+2,引用一次是cp[2]=c+1,再对这进行--,减后是c再引用是c[0]="ENTER"再+3,字符串指针指到"ER",输出是"ER" - printf("%s",*cpp[-2]+3);
这时cpp的值是cp+2,cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3,再引用是c[3]="FIRST",+3 字符串指针指到"ST",输出是"ST" - printf("%s\n",cpp[-1][-1]+1);
cpp还是cp+2,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2,再[-1]得*(c+2-1)=c[1]="NEW",+1字符串指针指到"EW",输出是"EW"。
#include <stdio.h>struct data{int a;unsigned short b;};int main(void){data mData;mData.b = 0x0102;char *pData = (char *)&mData;printf("%d %d", sizeof(pData), (int)(*(pData + 4)));return 0;}
输出:4 2
说明:一般变量都是从高到低分配内存地址,但对于结构体来说,结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的 “对齐”原则进行处理。
补充知识点:
除了栈以外,堆、只读数据区、全局变量地址增长方向都是从低到高的。
8:返回值加const修饰的必要性
你觉得下面两种写法有区别吗?
int GetInt(void) const int GetInt(void)
如果是下面的呢?其中A 为用户自定义的数据类型。
A GetA(void)const A GetA(void)
答案:没有任何区别。
解释:如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。所以,对于值传递来说,加const没有太多意义。
所以:
- 不要把函数int GetInt(void) 写成const int GetInt(void)。
- 不要把函数A GetA(void) 写成const A GetA(void)。
9:题看看下面的程序有几处错误
#include "stdafx.h"
#include <iostream>
using namespace std;
class Test
{
public:
int *p;
Test(int value){
p=new int(value);
}
~Test(){
cout<<"dd"<<endl;
delete p;
}
//Test(const Test& wang)
//{
// p = new int(*wang.p);
//}
void PrintValue()
{
cout<<"The value is"<<*p<<endl;
}
};
void Func(Test t)
{
cout<<"In the Func"<<endl;
}
int main(){
Test t1 =33;
Func(t1);
t1.PrintValue();
return 0;
}
解答:这道题是在 Func(t1) 这个语句开始出错的。原因是因为没有拷贝构造函数。所以在传参过程中会产生一个临时的变量,就是这个临时变量把p的地址析构了。才会在该函数执行完之后 成员p成为了一个野地址。
10: 输出变量的大小
(1)char *p;
(2)int *q[20];//这是一个指针数组
(3)int *m[20][20];
(4)int (*n)[10];//指向二维数组的指针
printf("%d",sizeof(p)); 他的大小为4
printf("%d",sizeof(q));他的大小为80
printf("%d",sizeof(m));他的大小为1600
printf("%d",sizeof(n));他的大小为4
解答:
(1):指针都是4个字节
(2):表示 20 个指向一个整数的指针。
(3):根据2来推导 有20 个指向指针数组,那么每个指针数组指向 20个指针,每个指针又指向一个整数。所以就是 20*20*4 = 1600
(4):表示指向"一群"指向 5 个整数数组的指针的指针。
11; 2维数组和3维数组怎样用一层循环打印出来
1,2,3
4,5,6
思路
行的最大值为1 为i/3%2,
列的最大值为2, 为i%3
int a[2][3]={1,2,3,4,5,6};
for(int i =0; i< 6;i++)
{
printf("%d ",a[i/3%2][i%3]);
}
{1,2,3} {4,5,6} {7,8,9}
{11,12,13}{14,15,16}{17,18,19}
思路:
行的最大值为1 为: i/行*列/2
列的最大值为1 为: i/3%2
其他: 为: i%3
char a[2][2][3]={{{1,6,3},{51,4,15}},{{3,5,33},{23,12,7}}};
for(int i=0;i<12; i++)
{
printf("%d ",a[i/6%2][i/3%2][i%3]); 或者 printf("%d ",*(&a[0][0][0]+i)); 或者
}
12:查看一个数组是否是升序
bool IsIncrease(int *a,int N)
{
return N<=1 || a[0]<=a[1] && IsIncrease(a+1,N-1) ;
}
13.有个数组a[100]存放了100个数,这100个数取自1-99,且只有两个相同的数,剩下的98个数不同,写一个搜索算法找出相同的那个数的值.(注意空间效率时间效率尽可能要低).
PS:鉴于以前某人说用int存储数组就是用了O(N)的辅助空间,现在假设是用char存储数组
int GetTheExtraVal(char*var,int size){int val;int i=0;for(;i<size;++i){if(var[var[i]&0x7F]&0x80){val=var[i]&0x7F;break;}var[var[i]&0x7F]|=0x80;}for(i>=0;--i){var[var[i]&0x7F]&=0x7F;}return val;}
给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url
可以估计每个文件的大小为50G×64=320G,远远大于内存限制的4G,不可能将其完全加载到内存中处理,考虑采取分而治之的方法。
· 第一步:遍历文件a,使用Hash函数将a文件中的url分别存储到1000个小文件中,如(a0....a999)这样每个小文件的大约为300M;遍历文件b,使用相同的Hash函数,将每个url存储到1000个小文件中,如(b0....b999)。这样,所有可能相同的url都存在对应的小文件中(a0对应b0),不对应的文件不可能存在相同的url。
· 第二步:求每对小文件中相同的url,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。
- 一道容易出错的笔试题
- 一道容易出错的java笔试题
- 一道容易出错的招聘笔试题
- 一道容易出错的笔试题
- 容易出错的Java笔试题
- c++ 容易出错的笔试题
- c 中容易出错的 细节
- C、C++容易出错的几个地方
- C/C++中容易出错的地方
- 容易出错的c-集锦-日积月累
- C语言容易出错的地方
- 几道容易出错的指针题
- C/C++ 关于字符串的处理容易出错的地方
- C语言中容易出错的几个地方
- C语言一些容易出错的优先级问题
- C语言中最容易出错的知识点
- C语言中容易出错的优先级运算
- C、C++语言容易出错的几个地方
- 那些未知
- 发邮件之Mutt详解
- 一步一步实现一个简单的OS(简单的让boot加载setup)
- PAT (Basic Level)1026. 程序运行时间
- IDEA使用--字体、编码和基本设置
- c++ 容易出错的笔试题
- 在Mysql存储过程中使用事务实例
- 尝试使用博客
- 前端资源大收集
- jdk和jre的区别
- Masonry自动布局
- 利用pl/sql创建oracle的table
- SCNetworkReachability与RealReachability示例整理
- CloudStack4.8在CentOS6.6下安装环境配置