C++小题(九)

/*
下面程序段的运行结果是()
int main(int argc, char *argv[])
{
    char *s = "abcdefg";
    s += 2;
    fprintf(stderr, "%d\n", s);
    return 0;
}

正确答案: C   你的答案: C (正确)

cde
字符"c"
字符"c"的地址
不确定

stdout -- 标准输出设备 。
stderr -- 标准错误输出设备
两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕。
*/
//////////////////////////////////////////////////////////////////
/*
以下哪个函数可以在源地址和目的地址的位置任意的情况下,在源地址和目的地址的空间大小任意的情况下实现二进制代码块的复制?
正确答案: B   你的答案: B (正确)

A memcpy()
B memmove()
C memset()
D strcpy()
memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,
memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。
但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
*/
//////////////////////////////////////////////////////////////////
/*
下面关于虚函数和函数重载的叙述不正确的是
正确答案: A   你的答案: A (正确)

A虚函数不是类的成员函数
B虚函数实现了C++的多态性
C函数重载允许非成员函数,而虚函数则不行
D函数重载的调用根据参数的个数、序列来确定,而虚函数依据对象确定

多态性分为编译时多态性和运行时多态性,
编译时多态性通过静态编联完成,例如函数重载,运算符重载;
运行时多态性则是动态编联完成,主要通过虚函数来实现;

函数重载不需要是成员函数,在类外声明或定义的函数同样可以对其进行重载

重载的调用主要根据参数个数,参数类型,参数顺序来确定, 函数重载是忽略返回值的
*/
//////////////////////////////////////////////////////////////////
/*
若有定义
typedef int * T; 
T a[10]; 
则a的定义与下面哪个语句等价?
正确答案: B   你的答案: B (正确)

int ( * a ) [ 10 ] ;
int * a [ 10 ] ;
int * a ;
int a [ 10 ] ;

typedef对已存在的类型使用一个新的名字,其中本题中int * 用T来代替,所以定义T a[ 10 ];就相当于是int * a[10];选项B正确。
*/
//////////////////////////////////////////////////////////////////
/*
以下定义错误的是:
正确答案: A   你的答案: A (正确)

struct A{A  _a};
struct A{A* _a;};
struct A{A& _a;};
struct B;struct A{B& _b;};struct B{A& _a;};
*/
//////////////////////////////////////////////////////////////////
/*
Which of the following calling convention(s) support(s) support variable-length parameter(e.g. printf)?
正确答案: A   你的答案: B (错误)

cdecl
stdcall
pascal
fastcall

函数调用约定(calling convention)函数调用约定不仅决定了发生函数调用时函数参数的入栈顺序,
还决定了是由调用者函数还是被调用函数负责清除栈中的参数,还原堆栈。函数调用约定有很多方式,
除了常见的__cdecl,__fastcall和__stdcall之外,C++的编译器还支持thiscall方式,不少C/C++编译器还支持naked call方式。
cdecl
    编译器的命令行参数是/Gd。__cdecl方式是C/C++编译器默认的函数调用约定,
	所有非C++成员函数和那些没有用__stdcall或__fastcall声明的函数都默认是__cdecl方式,它使用C函数调用方式,
	函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数,由于每次函数调用都要由编译器产生清除(还原)堆栈的代码,
	所以使用__cdecl方式编译的程序比使用__stdcall方式编译的程序要大很多,
	但是__cdecl调用方式是由函数调用者负责清除栈中的函数参数,所以这种方式支持可变参数,
	比如printf和windows的API wsprintf就是__cdecl调用方式。
*/
//////////////////////////////////////////////////////////////////
/*
请阅读下面代码片段并且回答问题:
#define SIZE_20M (20*1024*1024)
void func_a()
{
    char *temp = malloc(SIZE_20M)
    return;
}
void func_b()
{
    char temp[SIZE_20M];
    //...do something using temp
    return;
}

关于这段代码,下列说法正确的是
正确答案: B   你的答案: B (正确)

func_a 获得临时内存的方式效率通常更高。
func_b 使用了太多的栈,程序可能会在运行时候崩溃。
func_b 存在内存泄露
func_a 和func_b 分配的内存会自动初始化0

A   func_a()动态分配的数据位于堆区,func_b()的temp位于栈区,栈区的执行效率高于堆区,故func_b()效率高
C  func_b()中没有动态分配的内存,不存在泄露问题
D  都不会自动初始化为0,只有全局变量或者static变量会初始化为0
B  栈的空间一般为2M,分配太多栈空间程序肯定会崩溃
*/
//////////////////////////////////////////////////////////////////
/*
以下数字在表示为double(8字节的双精度浮点数)时存在舍入误差的有()。
正确答案: A B C   

2的平方根
10的30次方
0.1
0.5
100

A毫无疑问不用说
8字节的共64位,按照标准的浮点数表示方法,应该是1位符号位,11位指数位,52位尾数位
对于 B(2^90 < B < 2^100)来说,指数位是够了,但是尾数位会不会够呢? 
 B = 2^30*5^30 也就是说将B表示成二进制后,其后30位全为0,
 从其第一个不为0到最后一个不为0的二进制表示位中,至少需要90-30 = 60位来存储,
 而其尾数位只有52位,必然会产生舍入误差,所以B是的

对于C来说,将C表示成二进制便知 10[0.1] = 2[0.00011001100110011.......],亦为无限循环小数,
所以将0.1表示成二进制的double型必然也会产生舍入误差
*/
//////////////////////////////////////////////////////////////////
/*
下面有关C++的类和C里面的struct的描述,正确的有?
正确答案: A B C D   

A 在C++中,来自class的继承默认按照private继承处理,来自struct的继承默认按照public继承处理
B class的成员默认是private权限,struct默认是public权限
C c里面的struct只是变量的聚合体,struct不能有函数
D C++的struct可有构造和析构函数

c语言里不能直接定义函数,倒可以用函数指针
*/
//////////////////////////////////////////////////////////////////
/*
关于C++/JAVA类中static 成员和对象成员的说法正确的是?
正确答案: C   你的答案: C (正确)

A static 成员变量在对象构造时生成
B static 成员函数在对象成员函数中无法调用
C 虚成员函数不可能是static 成员函数
D static 成员函数不能访问static 成员变量

static为成员变量或函数,在类初始化是加载完成,可以被成员函数调用或访问
static成员函数既可以通过类名直接调用,也可以通过对象名进行调用
虚函数不可能是static的
static成员函数可以访问static成员变量
*/
//////////////////////////////////////////////////////////////////
/*
在c++中,
const int i = 0; 
int *j = (int *) &i; 
*j = 1; 
printf("%d,%d", i, *j)
输出是多少?
正确答案: A   
A 0,1
B 1,1
C 1,0
D 0,0

const修饰的常量值具有不可变性,c++编译器通常会对该变量做优化处理,在编译时变量i的值为已知的,
编译器直接将printf输出的变量i替换为0。尽管如此,编译器仍然会为变量i分配存储空间,
通过修改内存的hack方式将变量i在内存中的值修改后并不影响printf的输出。
如果将i更改为volatile const int类型的,编译器就不会对变量i做优化,printf输出的结果就为1。
*/
//////////////////////////////////////////////////////////////////
/*
Which of following C++ code is correct?
正确答案: C   

int f() { int *a = new int(3); return *a; }
int *f() { int a[3] = {1, 2, 3}; return a; }
vector<int> f() {vector<int> v(3); return v; }
void f(int *ret) { int a[3] = {1, 2, 3}; ret = a; return; }

因为C不存在内存泄露的问题且可以得到想要结果,但所有选项都是可以编译通过的,无语法错误。
A是内存泄露,没有delete,B数组是临时的,根本传不到主调函数里,D的问题同B一样。
*/
//////////////////////////////////////////////////////////////////
/*
int main(void)
{
    vector<int>array;
    array.push_back(100);
    array.push_back(300);
    array.push_back(300);
    array.push_back(500);
    vector<int>::iterator itor;
    for (itor = array.begin(); itor != array.end(); itor++)
    {
        if (*itor == 300)
        {
            itor = array.erase(itor);
        }
    }
    for (itor = array.begin(); itor != array.end(); itor++)
    {
        cout << *itor << " ";
    }
    return 0;
}

正确答案: B   

100 300 300 500
100 300 500
100 500

在第一个循环内,通过迭代器将array中的元素删除之后,迭代器指向的是被删元素的下一个,
在进行了一次itor++操作之后,指向了被删除元素的后边第二个。所以此循环中有一个“300”没有被删掉。
*/
//////////////////////////////////////////////////////////////////
/*
以下代码的输出结果是?
main() { 
    char str[]="S\065AB"; 
    printf("\n%d", sizeof(str)); 
}
正确答案: C   

7
6
5
error
 转义字符\ddd表示8进制,所以就有 4个字符 + '\0' 即5
*/
//////////////////////////////////////////////////////////////////
/*
#include <stdio.h>
#include <stdio.h>
void fun( char *s )
{
    char a[10];
    strcpy ( a, "STRING" );
    s = a ;
}
main( )
{
    char *p= "PROGRAM" ;
    fun( p );
    printf ( "%s\n ", p) ;
}
程序运行后的输出结果是(此处□代表空格)?
正确答案: D   你的答案: D (正确)

STRING
STRING□□□□
STRING□□□
PROGRAM
本题考查字符串指针作为函数参数,p作为字符串指针传入fun中,p指向的内容并没有发生变化,所以选项D正确。
fun()是一个传址函数,传入的地址是原地址的复制,s=a改变了s的内容(如果在fun里面输出s,结果是STRING),但并没改变p的值,更没有改变其指向的内容。
*/
//////////////////////////////////////////////////////////////////
/*
将“引用”作为函数参数有哪些特点?
正确答案: B C D   你的答案: B C D (正确)

A引用传递和指针传递没有差别
B传递引用给函数与传递指针的效果是一样的
C使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;
D指针传递下,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

(1)传递引用给函数与传递指针的效果是一样的。
	这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,
	所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;
	而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;
	如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,
	但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,
	这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
*/
//////////////////////////////////////////////////////////////////
/*
有函数定义: 
void test(int a){} 
void test(float a){} 
则以下调用错误的是:
正确答案: D   

test(1);
test(‘c’);
test(2+’d’)
test(0.5)

0.5是double类型,既匹配int类型也匹配float类型,应该写成0.5f
*/
//////////////////////////////////////////////////////////////////
/*
以下不能作为合法常量的是:
正确答案: B   

1.234e04
1.234e0.4
1.234e+4
1.234e0
e后面的代表指数,也就是e的n次方,不能是浮点数
*/
//////////////////////////////////////////////////////////////////
/*
在C++中,为了让某个类只能通过new来创建(即如果直接创建对象,编译器将报错),应该()
正确答案: B   

将构造函数设为私有
将析构函数设为私有
将构造函数和析构函数均设为私有
没有办法能做到

编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,
编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。 
因此,将析构函数设为私有,类对象就无法建立在栈(静态)上了,只能在堆上(动态new)分配类对象 。
*/
//////////////////////////////////////////////////////////////////
/*
若以下程序
#include <stdio.h>
main()
{ 
    FILE *fp;
    int i,a[ 6]={1,2,3,4,5,6},k;
    fp = fopen ("data.dat", "w+b");
    for (i=0;i<6;i+ +)
    { 
        fseek(fp,0L,0);
        fwrite(&a[5—i],sizeof(int),1,fp);
    }
    rewind(fp);
    fread(&k,sizeof(int),1,fp);
    fclose(fp);
    printf("%d",k);
}
则程序的输出结果是?
正确答案: B   

6
1
123456
21
因为循环调用fseek函数,每次都是写入开头位置。rewind()指向开头,输出1。
*/
//////////////////////////////////////////////////////////////////
/*
在int p[][4]={{1},{3,2},{4,5,6},{0}};中,p[1][2]的值是()
正确答案: B   你的答案: B (正确)
1
0
6
2

注意默认值为0
*/
//////////////////////////////////////////////////////////////////
/*
以下说法正确的是?
正确答案: B D   

在多线程中不加限制的随意访问非static局部变量不会导致运算结果出错
在多线程中不加限制的随意访问非static全局变量可能会导致运算结果出错
在多线程中不加限制的随意访问static局部变量不会导致运算结果出错
在多线程中不加限制的随意访问static全局变量可能会导致运算结果出错

无论是static还是非static的全局变量,如果不加限制随意访问的话易出现同步问题。
无论是static还是非static的局部变量,每个线程都是私有的,其他线程不会对其进行干扰。
*/
//////////////////////////////////////////////////////////////////
/*
CONTAINER::iterator iter , tempIt;
for (iter = cont.begin() ; iter != cont.end() ; )      
{
    tempIt = iter;
    ++iter;
    cont.erase(tempIt);
      
}
 
假设cont是一个CONTAINER的示例,里面包含数个元素,那么当CONTAINER为: 1、vector 2、list 3、map 4、deque 
会导致上面的代码片段崩溃的CONTAINER类型是?
正确答案: A   

1,4
2,3
1,3
2,4

关联容器(如map, set, multimap,multiset),删除当前的iterator,只会使当前的iterator失效,只要在erase时,递增当前iterator即可。
对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。
这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。
不过erase方法可以返回下一个有效的iterator
list使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator。
*/
//////////////////////////////////////////////////////////////////
/*
不可重载运算符包括  ?: :: . .*这四个
*/
//////////////////////////////////////////////////////////////////
/*
通用多态是指
正确答案: D   你的答案: D (正确)

强制多态和包含多态
重载多态和强制多态
参数多态和重载多态
包含多态和参数多态

重载多态和强制多态是 指特定多态。
参数多态和包含多态是指通用多态。
在c++语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现。
类型参数化多态和包含多态统称为一般多态性,用来系统地刻画语义上相关的一组类型。
重载多态和强制多态统称为特殊多态性,用来刻画语义上无关联的类型间的关系
*/
//////////////////////////////////////////////////////////////////
/*
int func(int a)
{
    int b;
    switch (a)
    {
        case 1: b = 30;
        case 2: b = 20;
        case 3: b = 16;
        default: b = 0;
    }
    return b;
}
则func(1) = ?
正确答案: D   

30
20
16
0
因为没有break语句,所以会一直执行,每次执行之后,b的新值会覆盖原来的值。所以应该是b=0
*/
//////////////////////////////////////////////////////////////////
/*
在重载一个运算符为成员函数时,其参数表中没有任何参数,这说明该运算符是 ( )。
正确答案: C   

无操作数的运算符
二元运算符
前缀一元运算符
后缀一元运算符

*/
//////////////////////////////////////////////////////////////////////
/*
C++中构造函数和析构函数可以抛出异常吗?
正确答案: C   你的答案: B (错误)

都不行
都可以
只有构造函数可以
只有析构函数可以

 1.不建议在构造函数中抛出异常;
2.构造函数抛出异常时,析构函数将不会被执行,需要手动的去释放内存

1.析构函数不应该抛出异常;
2.当析构函数中会有一些可能发生异常时,那么就必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外;
3. 析构函数异常相对要复杂一些,存在一种冲突状态,程序将直接崩溃:异常的被称为“栈展开(stack unwinding)”【备注】的过程中时,
从析构函数抛出异常,C++运行时系统会处于无法决断的境遇,因此C++语言担保,当处于这一点时,会调用 terminate()来杀死进程。
因此,当处理另一个异常的过程中时,不要从析构函数抛出异常, 抛出异常时,其子对象将被逆序析构
*/
////////////////////////////////////////////////////////
/*
类成员函数的重载、覆盖和隐藏区别描述正确的有?
正确答案: C D   

覆盖是指在同一个类中名字相同,参数不同
重载是指派生类函数覆盖基类函数,函数相同,参数相同,基类函数必须有virtual关键字
派生类函数与基类函数相同,但是参数不同,会"隐藏"父类函数
函数名字相同,参数相同,基类无virtual关键字的派生类的函数会"隐藏"父类函数
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
*/
////////////////////////////////////////////////////////////////
/*
类A是类B的友元,类C是类A的公有派生类,忽略特殊情况则下列说法正确的是()
正确答案: B D   

类B是类A的友元
类C不是类B的友元
类C是类B的友元
类B不是类A的友元

(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。
友元关系是单向的,不是对称,不能传递。
关于传递性,有人比喻:父亲的朋友不一定是儿子的朋友。
那关于对称性,是不是:他把她当朋友,她却不把他当朋友
*/
///////////////////////////////////////////////////////
/*
下面代码输出什么
#include<stdio.h>
int main( )
{
    unsigned int a = 6;
    int b = -20;
    (a + b > 6) ? printf(">6") : printf("<=6");
    return 0;
}
输出结果是 >6
程序的运算要求一致的数据类型,通常低类型向高类型转换。
占内存字节数少的数据类型向占字节数多的类型转换以保证不损失精度。
int和unsigned int都是4字节,但是int有一个符号位,相当于数据位较少,向unsigned int型转换,
b转成unsigned int后等于4294967276,所以导致a+b>6
*/

你可能感兴趣的:(C++小题(九))