您的位置:首页 > 编程语言 > C语言/C++

[整理自用]c++错题(长期更新)

2018-03-06 16:44 197 查看

内存占用空间

题目:若char是一字节,int是4字节,指针类型是4字节,代码如下:

class CTest
{
public:
CTest():m_chData(‘\0’),m_nData(0){ };
virtual void mem_fun(){};
private:
char m_chData;
int m_nData;
static char s_chData;
};
char CTest::s_chData=’\0’;//静态成员一般不可以在类内初始化,但是const的可以。


问题:

(1)若按4字节对齐sizeof(CTest)的值是多少? 12

(2)若按1字节对齐sizeof(CTest)的值是多少? 9

分析:

1 先找有没有virtual 有的话就要建立虚函数表,+4

2 static的成员变量属于类域,不算入对象中 +0

3 神马成员都没有的类,或者只有成员函数 +1

4 对齐法则(少的算多的)

其他:

1.sizeof的本质是得到某个类型的大小,即创建这个类型的一个对象(或变量)的时候,需要为它分配的空间的大小。

2.static成员变量是存储在静态区当中,是一个共享的量。因此,创建实例对象时,无需再为static成员变量分配空间。

综上,sizeof计算类的大小的时候会忽略static成员变量的大小。

显式调用重载的运算符函数

题目:已知表达式++a中的”++”是作为成员函数重载的运算符,则与++a等效的运算符函数调用形式为:

a.operator++();


要点分析:

当重载运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数显式参数数目比运算对象数目少一个。(C5 P490)

递增(递减)运算符显式调用(C5 P504)

前置版本:
a.operator++();


后置版本:
a.operator++(0);


格式化输出

题目:以下程序的运行结果是()

int main(void)
{
printf("%s , % 5.3s\n","computer","computer");
return 0;
}


要点分析:

1. %m.ns 表示输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的右侧,左补空格。

2. 格式化输出如果规定了输出列的,不够的时候是右对齐,左侧补零。够了就全部输出。

4000

答案:
computer,com


题目:假设在一个 32 位 little endian (小端模式) 的机器上运行下面的程序,结果是多少? ( 1,0,2)

#include <stdio.h>
int main()
{
long long a = 1, b = 2, c = 3;
printf("%d %d %d\n", a, b, c);
return 0;
}


要点分析:

long在32位机器是4字节,在64位机器是8字节,但是long long,不管在哪个机器都是8字节;(后续再博客里会整理的)

printf函数的原型是printf(const char*,…);

printf函数是自右向左一股脑压入栈的;

%d输出的是4个字节,int类型所占的字节数。

有了上述四条,本题目就相对比较简单了。由于
a,b,c
long long
类型,占8个字节,因此:



不知道算什么

问题: math.h的abs返回值( )?

要点分析:

c中的函数申明为 int abs(int num);

int取值范围是负数比正数多1的,因此:

1. num为0或正数时,函数返回num值;

2. 当num为负数且不是最小的负数时,函数返回num的对应绝对值数,即将内存中该二进制位的符号位取反,并把后面数值位取反加一;

3. 当num为最小的负数时,由于正数里int类型表示不了这个数的绝对值,所以依然返回该负数。

函数调用约定

详细内容见其他人的博客带你玩转Visual Studio——调用约定__cdecl、__stdcall和__fastcall

这里仅仅只是拿过来做整理之用。

要点__cdecl__stdcall__fastcall
参数传递方式右->左右->左左边开始的两个不大于4字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数自右向左压栈传送
清理栈方法调用者清理被调用函数清理被调用函数清理
适用场合C/C++、MFC的默认方式; 可变参数的时候使用;Win API要求速度快
C编译修饰约定_functionname_functionname@number@functionname@number

优先级

题目:设有定义语句

int x[6]={2,4,6,8,5,7};
int *p=x;
int i=0;


要求依次输出x数组6个元素中的值,能完成此操作的语句是:
for(i=0;i<6;i++) printf("%2d",*(p++));


分析:

尽管()是最高优先级,但是仅仅只是优先将()内的符号进行结合,而不表示一定先对()内进行计算。所以尽管有括号(),但由于
*
++
优先级相同,而且是右结合,所以事实上
*(p++)
等同于
*p++


题目:设x、y、t均为int型变量,则执行语句后,变量t和y的值分别为__。

t=3;
x=y=2;
t=x++||++y;


分析:

1.
||
运算符与
|
。前者是判断表达式最后的结果是真是假,所以只可能是0/1。我开始都没在题目答案中找到 t=1t=1这个答案,这也是答错的重要原因。

2. 运算优先级,赋值运算优先级是很低的。

3.
||
,只要前一个表达式为真,则后面一个表达式不做运算了;不然才会继续进行后面表达式的计算。同理
&&
,若前一个表达为假,则不会继续对后面的表达式进行计算了。

答案: t=1,y=2t=1,y=2.

时间复杂度

题目:

在一台主流配置的PC机上,调用f(35)所需的时间大概是__。(几分钟)

int f(int x) {
int s=0;
while(x-- >0)
s+=f(x);
return max(s,1);
}


这道题实质上是考时间复杂度的。由于递归是在循环里的,所以其时间复杂度:

O(f(35))=O(f(34))+O(f(33))+…+O(f(0))=235235O(f(0))。现在的计算机大致每秒运算一亿次。所以大约花去235235/100000000m大致为344秒也就是几分钟。

malloc and free

c/c++ new与malloc的区别及使用时注意的问题

malloc 函数详解

其他:

malloc 和 free:是管理虚拟内存;所以当然可以通过malloc(size_t)函数调用申请超过该机器物理内存大小的内存块。

同理,无法通过内存释放函数free(void*)直接将某块已经使用完的物理内存直接还给操作系统。(此外,可能是程序结束才还给操作系统)。

结构体

题目:以下定义错误的是:a)

a)    struct A{A  _a;};
b)    struct A{A * _a;};
c)    struct A{A & _a;};
d)    struct B;
struct A{B & _b;};
struct B{A & _a;};


题目要点分析:

1. 结构体在完成定义之前是incomplete type(不完全类型),不完全类型不能定义对象,只能定义引用和指针,或者用于声明函数的形参和返回值类型

2. struct成员类型不可以是它自己。

否则会导致递归定义。 理论上这样导致结构体的大小不能被计算(无限大小)。

但是成员可以定义为该结构体的指针(引用在c++底层是用指针实现的,所以也可以),因为指针的大小是已知的。

纯虚函数与抽象基类

以下内容取自《c++ premier第五版》P540-542页。

将虚函数声明语句分号之前书写=0就可以将虚函数定义为纯虚函数。

上述=0 只能出现在类内部的虚函数声明语句处。

含有(或未经覆盖直接继承)的纯虚函数的类是抽象基类。且我们不能直接为抽象基类创建对象。

派生类必须覆盖纯虚函数给出自己的定义,否则它们仍然是抽象基类。

派生类的构造函数只能初始化其直接基类。仍然需要调用抽象基类自己的构造函数来初始化其成员。

纯虚函数可以有函数体,但是定义必须在类的外部。

虚函数可以是另一个类的友元函数,但不能是静态成员函数:

友元函数不能是虚函数,因为友元函数不可以继承.

在基类中声明了虚函数,在派生类中如果不声明,则默认为虚函数。(因此,不一定在派生类中显示声明。)

组合和继承

c++继承和组合的区别

总结:

1. 组合也叫“对象持有”,就是在类中定义另一类型的成员。组合拥有良好的扩展性,支持动态组合,因此请优先考虑组合方法;

2. 继承会破坏类的独立性,增加系统的复杂性,一般系统的继承层次不超过3层。

组合和继承优缺点:

组 合 关 系继 承 关 系
优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
优点:具有较好的可扩展性缺点:支持扩展,但是往往以增加系统结构的复杂度为代价
优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象缺点:不支持动态继承。在运行时,子类无法选择不同的父类
优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口缺点:子类不能改变父类的接口,但子类可以覆盖父类的接口
缺点:整体类不能自动获得和局部类同样的接口优点:子类能自动继承父类的接口
缺点:创建整体类的对象时,需要创建所有局部类的对象优点:创建子类的对象时,无须创建父类的对象

异常处理

题目:下列关于异常处理的描述中,理解不正确的是:

1. C++语言的异常处理机制通过3个保留字throw、try和catch实现。

2. 任何需要检测的语句必须在try语句块中执行,并由throw语句抛出异常。

3. throw语句抛出异常后,catch利用数据类型匹配进行异常捕获。

4. 一旦catch捕获异常,不能将异常用throw语句再次抛出。(错误)

catch异常后,同样可以用throw语句在此抛出,如果没有解决,会直接向上层继续抛,直至main函数,然后异常停止!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: