C/C++易错点

C/C++易错点

1-20

1.假定一个类的构造函数为A(int aa,int bb){a=aa–;b=a*bb;},则执行A x(4,5);语句后,x.a和x.b的值为?

解析:4和20。
① a==aa; //a=4 aa=4
② aa–; //a=4 aa=3
③ b=abb; //b=45=20


2.如果有
#define AREA(a+b)a+b;
则语句
int s=AREA(3,4)*AREA(3,4)
执行后变量s的值为

解析:19。对于宏定义的使用,先替换,再按优先级计算


3.关于引用以下说法错误的是()

A.引用必须初始化,指针可以不初始化
B.引用初始化以后不能改变,而指针可以改变指向
C.不存在指向空值的引用,但是存在指向空值的指针
D.一个引用可以看作是某个变量的一个“别名”
E.引用传值,指针传地址
F.函数参数可以声明为引用或指正类型

解析:E。引用传地址


4.以下变量分配在BSS段的是()

char s1[100];
int s2=0;
static int s3=0;
int main(){
    char s4[100];
}

解析:A。
bss:未初始化全局变量
data:已初始化全局变量
text:代码段
heap:堆
stack:栈


5.下述有关虚函数和纯虚函数说法正确的是()
A.被virtual关键字修饰的成员函数,就是虚函数
B.在基类中实现纯虚函数的方法是在函数原型后加=0,virtual void funtion()=0;
C.同时含有纯虚函数的类称为抽象类,它可以被实例化,但是对象不可以调用纯虚函数
D.使用纯虚函数的意义是在很多情况下,基类本身生成对象是不合情理的

解析:C。抽象类的定义:在c++中,含有纯虚函数的类称为抽象类,它不能生成对象。抽象类是不完整的,它只能用作基类。抽象类不能被实例化,但是能作为指针或引用指向派生类的对象或函数。虚函数和纯虚函数的区别 | 菜鸟教程


6.关于虚函数,正确的描述是()
A.构造函数不能是虚函数
B.析构函数不能是虚函数
C.虚函数可以是友元函数
D.虚函数可以是静态成员函数

解析:A。C++规定构造函数不能是虚函数,而析构函数可以是虚函数。虚函数依赖于虚表,虚表需要在构造函数中初始化,通过初始化虚指针来指向正确的虚表,但是在构造对象期间,虚表还没有被初始化。


7.下面程序的输出是什么?

int main(){
    int a[5]={1,2,3,4,5};
    int *p=(int *)(&a+1);
    printf(%d %d,",*(a+1),*(p-1));
    return 0;
}

解析:2 5。
(a+1)即a[1];
指针+1所得结果要根据指针类型加上一定的值。
本题:a为长度为5的int数组指针,p=&a+5
sizeof(int)
最后*(p-1)即指向为a[4]


8.下面程序完成后x的值为:

void main(){
    int x;
    x=printf("pikaqiu")//"7个字符"
    printf("x=%d" ,x);
}

解析:x=7。int printf(const char*format,…);返回值:正确返回输出的字符总数,错误返回负值,同时,,输入输出错误标志将被置值,可由指示器ferror来检查输入输出的错误标志。


9.C语言中引入++运算符的目的是为了提高编译后的目标程序的运行效率。Y/N

解析:否。++会降低程序的运行效率但会使代码更精简。


10.下面那种情况下,B不能隐式转换为A?
A.class B:public A{}
B.class A:public B{}
C.class B{operator A();}
D.class A{A(const B&);}

解析:B。
A:派生类转化基类
B:基类转派生类,不能隐式转化
C:operator除了重载外,还可表示隐式类型转换操作符
D:拷贝构造函数,B b;A a=b;


11.如果x=2014,下面函数的返回值为()

int fun(unsigned int x){
    int n=0;
    while(x+1)
    {
        n++;
        x=x|(x+1);
    }
}

解析:23。x=x|(x+1);每次都将x从右往左第一个0变1,直至全为1溢出。
x=x|(x+1)统计0的个数,x&(x-1)统计1的个数。unsigned int == 32位


12.通用多态是指()

A.强制多态和包含多态
B.重载多态和强制多态
C.参数多态和重载多态
D.包含多态和参数多态

解析:D。 此外,重载多态和强制多态为特定多态。

1.参数多态:函数模板和类模板
2.包含多态:含有virtual关键字
3.重载多态:相同函数名,但函数的参数个数或参数类型不同,或者函数类型不同
4.强制多态:强制类型转换


13.下列关于内存分配和释放的函数及其区别描述正确的有(多选)
A.C++语言的标准内存分配函数:malloc、calloc、realloc、free等。
B.C语言的标准内存分配函数为new/delete
C.malloc和calloc的区别是1块和n块的区别和初始化
D.realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小扩容到size;

解析:CD。


14.以下说法正确的是()
A.内联函数inline改善了函数调用的执行效率
B.类A的友元(friend)函数可以访问类A的私有成员
C.类A的友元(friend)类B可以访问类A的私有成员
D.类A的静态数据成员为类A的所有对象所共享
E.类A的静态成员函数没有传递this指针作为参数

解析:全对。E静态与非静态成员函数之间的区别即为:静态成员函数没有this指针。


15.见如下代码,若要实现数组内两个数值交换的功能。代码//可以为:(多选)

int arr[2] ={10,20};
void change(int *p){
    /*......*/
}

A.  int temp=p[0];      
    p[0]=p[1];             
    p[1]=temp;
B.  p[0]=p[0]^p[1];
    p[1]=p[0]^p[1];
    p[0]=p[0]^p[1];
C.  int n1=p[0];
    int n2=p[1];
    int temp=n1;
    n1=n2;
    n2=temp;
D.  int temp=*0;
    *p=*(p+1);
    *(p+1)=temp;

解析:ABD。C仅局部变量值交换。^异或 (相同出0,不同出1)。


16.以下描述正确的是
A.在C++中数据封装是通过各种类型来实现的
B.在C++中,数据封装可以由struct关键字提供
C.数据封装就是使用结构类型将数据代码连接在一起
D.数据封装以后,仍然可以不通过使用函数就能直接存取数据

解析:BD。A,由类来实现。


17.有声明
int fun(int);
int (*pf)(int) =fun ;
在下列选项中,正确的调用是()
A.int a=15;int n=fun(&a);
B.int a=15;cout<<(&pf)(a);
C.cout<<(pf)(256);
D.cout<<pf(256);

解析:CD。函数指针 int (*pt)(int) 表示pt指向一个函数类型为int,拥有一个int型参数的函数 而int pt(int)则表示pt为函数名,函数返回的是一个int类型的指针,有一个int型的参数 函数指针的使用方式: (1)pt(int) (2)(*pt)(int) (3)(pt)(int)


18.下面有关C++类说法正确的是()
A.对基类成员的访问必须是无二义性的
B.基类的公有成员在派生类中仍然是公有的
C.this指针保证基类保护成员在子类中可以被访问
D.派生类一般很少用私有派生

解析:AD。B基类的公有成员在派生类中权限由派生规则决定。C.this指针保证基类保护成员在本类中可以被访问。


19.设有以下定义,值为5的枚举常量是( )。
enum week{sun,mon, tue=3,wed,thu,fri, sat,}w
A.tue B.sat C.thu D.fri

解析:C。
枚举类型定义形式:enum typeName (valueName1, valueName2, valueName3, …);
1 如果给定枚举名字,未给名字对应值时,枚举值默认从0开始,往后逐个加1
2 如果给定某个枚举名字和枚举名,往后的值就从给定枚举值开始,逐个往后递增1


20.64位电脑运行C++结果输出()

#include<iostream>
using namespace std;

class A{
    char a[2];
public:
    virtual void aa() {};
};

class B:public virtual A{
    char b[2];
    char c[2];
public:
    virtual void bb(){};
    virtual void aa(){};
};
class C:public virtual B{
    char a[2];
    char b[2];
    char c[2];
public:
    virtual void cc(){};
    virtual void aa(){};
    virtual void bb(){};
    
};

A.8 16 24
B.16 32 36
C.16 32 48
D.8 20 24

解析:C。
对于对象A,包含一个虚函数指针,因此对其到8字节,然后有2个char型,最后补齐到8字节整倍数,因此其长度为16。
对于对象B,包含一个虚函数指针,也是对其到8字节,然后有4个char型,最后补齐到8字节整倍数,变成16字节。然后加上对象A的大小,共计32字节。
对于对象C,包含一个虚函数指针,也是对齐到8字节,然后是6个char型,最后补齐到8字节整倍数,变成16字节。然后加上对象B的大小,共计48字节。


21-40

21.关于虚函数和纯虚函数,以下说法正确的是(多选)
A.子类必须重载父类里的虚函数
B.子类必须重载父类里的纯虚函数
C.虚基类的构造函数在非虚基类之前调用
D.带有纯虚函数的类不能直接实例化

解析:CD。AB:子类实现父类虚函数叫重写,不叫重载。父类有纯虚函数,子类可以不实现,此时子类仍是抽象类。C:最终继承类构造函数中,成员初始化列表同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。


22.sizeof(“hello”);strlen(“world”);两个语句的值分别为:

解析:6,5。C++中sizeof是运算符,可以得到字符串所占内存大小,包括最后的‘\0’。strlen函数则不包括最后的‘\0’。


23.以下叙述中正确的是()
A.语句int a[8]={0};是合法的
B.语句int a[]={0};是不合法的,遗漏了数组的大小
C.语句char a[2]={“A”,“B”};是合法的,定义了一个包含两个字符的数组
D.语句char a[3];a=“AB”;是合法的,因为数组有三个字符空间的容量,可以保存两个字符

解析:A。AB对,C应为char a[2]={‘A’,‘B’};
D.数组变量char a[3]时,a是常量指针,地址固定不可更改(char* const)


24.静态变量和外部变量都是全局变量,它们的存储是静态的。请问这句的说法是正确的吗?

解析:静态变量分为局部静态变量和全局静态变量,局部静态变量不是全局变量。


25.变量void(*s[5])(int)表示意思为()
A.函数指针
B.函数指针数组
C.数组指针函数
D.语法错误

解析:函数指针的定义方式为:函数返回类型(*指针变量名)(函数参数列表);


26.以下描述中,()是错误的。
A.内联函数的主要解决程序的运行效率问
B.内联函数的定义或声明必须出现在内联函数第一次被调用之前
C.内联函数中可以包括各种语句
D.对内联函数不可以进行异常接口声明

解析:C。递归函数不能定义为内联函数,复杂语句则不适合内联函数


27.以下哪个函数可以在源地址和目的地址的位置任意的情况下,在源地址和目的地址的空间大小任意的情况下实现二进制代码块的复制?
A.memcpy() B.memmove() C.memset() D.strcpy()

解析:B。
void *memcpy( void *to, const void *from, size_t count ):功能:函数从from中复制count 个字符到to中,并返回to指针。 如果to 和 from 重叠,则函数行为不确定。
void *memmove( void *to, const void *from, size_t count ):功能:与mencpy相同,不同的是当to 和 from 重叠,函数正常仍能工作。
void *memset( void *buffer, int ch, size_t count ):功能: 函数拷贝ch 到buffer 从头开始的count 个字符里, 并返回buffer指针。 memset() 可以应用在将一段内存初始化为某个值。
char *strcpy( char *to, const char *from ):功能:复制字符串from 中的字符到字符串to,包括空值结束符。返回值为指针to。


28.代码:

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类型为哪些?

解析:1,4。对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator,cont.erase(iter++)可以修改为cont.erase(iter)


29.const char*str=“123456”;,sizeof(str)和strlen(str)的结果分别是()

解析:64位系统输出值为8,6。32位系统输出值为4,6。


30.以下代码的运行结果为()

#include<iostream>

#include<string>

using namespace std;

class B0{

public:

  virtual void display(){ cout<<"B0";}

};

class B1:public B0{

public:

  void display(){cout<<"B1";}

};

class D1:public B1{

public:

  void display(){cout<<"D1 ";} 

};

void fun(B0 ptr){

  ptr.display();

}

int main(){

  B0 bo; B1 b1; D1 d1;

  fun(b0);

  fun(b1);

  fun(d1);

}

解析:B0 B0 B0 。
虚函数的动态绑定仅在基类指针或绑定派生类对象时发生。这里使用的不是按地址传递,这样会转化为基类对象,直接调用基类的成员函数。如果是void fun(B0 *ptr)或void fun(B0 &ptr)则可以实现多态(B0 B1 D1)。


31.若PAT是一个类,则程序运行时。语句“PAT(*ad)[3];”调用PAT的构造函数的次数为?

解析:0。
1.语句表示数组指针即指向三个数组的指针;2.数组虽有三个对象但并没有实例化。


32.请指出以下程序的错误(多选):

void GetMemory(char **p,int num){
	if(NULL ==p && num<=0)//1
	return;
	*p= (char*)malloc(num);
	return ;
}
void main(void){
	char *str=NULL;
	GetMemory(&str,80);//2
	if(NULL !=str){
		strcpy(&str,"hello");//3
	}
	return true;//4
}

解析:1,3,4。
1.if(NULL ==p || num<=0)
3.strcpy(str,“hello”)
4.return void;


33.以下逗号表达式的值为()
(x=4*5, x *5), x+25

解析:45


34.设有语句
int a = 5, b;
b = a > 3 && 0, a++;
执行后变量 b 的值为__________()

解析:6


阅读如下程序,该程序的执行结果为?
#include "stdio.h"
class A
{
public:
    virtual void Test()
    {
        printf("A test\n");
    }
};
class B: public A
{
public:
    void func()
    {
        Test();
    }
    virtual void Test()
    {
        printf("B test\n");
    }
};
class C: public B
{
public:
    virtual void Test()
    {
        printf("C test\n");
    }
};
int main()
{
    C c;
    ((B *)(&c))->func();
    ((B)c).func();
}

解析:C test B test。
(( B *)(& c ))-> func (); 是多态行为 (( B ) c ). func (); 不是多态行为。


36.对于下面的说法,正确的是____。

A.对于 struct X { short s; int i; char c; },sizeof(X) 的值等于 sizeof(s) + sizeof(i) + sizeof(c)
B.对于某个double变量 a,可以使用 a == 0.0 来判断其是否为零
C.初始化方式 char a[14] = "Hello, world!"; 和初始化方式 char a[14]; a = "Hello, world!"; 的效果相同
D.在gcc编译器下,对于 int i = 3; printf("%d %d", ++i, ++i),运行输出为:4 5
E.以上选项均不正确

解析:E.
C.后面初始化错误 D.输出5 5


37.What’s the output of below code on a 64-bit system?(单选)

#include <iostream>
using namespace std;
struct data {
int type;
struct {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:4;
    unsigned int d:4;
    unsigned int e:4;
    unsigned int f:4;
    unsigned int g:4;
    unsigned int h:8;
    unsigned int i:8;
} flags;
struct {
    unsigned int a:1;
    unsigned int b:1;
} flagsEx;
};
int main() {
    data temp;
    int a = sizeof(data);
    int b = sizeof(temp);
    data *pTemp = new data();
    int c = sizeof(pTemp);
    delete pTemp;
    pTemp = NULL;
    cout << a << ", " << b << ", " << c << endl;
    return 0;
}

​A.16 16 8
B.48, 48, 8
C.48, 16, 8
D.16, 4, 4

解析:A.
unsigned int a:1;不是给a赋初值,在内存中存取数据的最小单位一般是字节,但有时存储一个数据不必用一个字节。这是一种位域的结构体,这个结构里a占用的是一个字节中的1位,b也占用1位.所以这里的a和b的取值只能是0和1。因为它们都是用1位来表示的。使用位域可以节省很多的内存空间。
并且存储器会按照其定义类型预留存储bit位空间,即
struct {

     unsigned int a:1;
    unsigned int b:1;
    unsigned int c:4;
    unsigned int d:4;
    unsigned int e:4;
    unsigned int f:4;
    unsigned int g:4;
    unsigned int h:8;
    unsigned int i:8;
} flags;

共占用38个bit,但一个unsigned int占四个字节共32个bit,多出的6个bit占四个字节,多出来的是预留空间;

同理 struct {
unsigned int a:1;
unsigned int b:1;
} flagsEx;

也占四个字节;

sizeof针对类型,a,b输出的都是struct data 的大小,所以a=b=4+8+4=16;

c输出的是指针的大小,所以c=64/8=8;

/**********************************************************************/

关于预留空间的补充:预留空间是针对最大bit类型的,如

仅改变 flagsEx

struct {
unsigned char a:1;
unsigned int b:1;
} flagsEx;

flagsEx任然占用4个字节;a,b,c结果不变

仅改变 flagsEx

struct {
unsigned long a:1;
unsigned int b:1;
} flagsEx;

则flagsEx占用8个字节;但会改变flags和 int type的最小占用单位变为8个字节,
结果a=b=24;但是sizeof(type)任然等于4;
仅将int type 改为long type结果结果a=b=24;但是sizeof(flagsEx)任然等于4;
也就是说flagsEx 、flags、type中最大类型决定了data最小存储单位,存储位数不够则增加一个最小存储单位;


38.有以下程序,程序运行后的输出结果是()

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
  int m=0123, n = 123;
  printf("%o %o\n", m, n);
  return 0;
}

解析:123 173
o% 表示8进制进行输出int m=0123; m已经是8进制不需要进行转换 而n=123是10进制 需要进行8进制转换 得173。
数字前加0表示八进制数,加0x表示16进制。


39.k为unsigned int类型,以下while循环执行次数为()

unsigned int k = 20;
while (k >= 0)
    --k;

解析:无限次
k为unsigned,永远大于等于0。


40.对于以下C++程序代码输出是a = _ , p = _ 。

#include <iostream> 
using namespace std; 
int main(void) 
{ 
    const int a = 10; 
    int * p = (int *)(&a); 
    *p = 20; 
    cout<<"a = "<<a<<", *p = "<<*p<<endl; 
    return 0; 
} 

解析:a = 10, p = 20
其实这道题真正的答案是不确定的,他与编译器有关,在C++标准中并没有强制规定将一个const
常量转换为一个非const后应该怎么办,这个是交给编译器设计者来决定的,以VS为例子,如果建立的是.c文件,也就是在纯c的环境下编译该代码,输出的结果将会是20 20,但是如果是C++则是10,20。它真正的处理原理如下,a作用域下在C++中所有的常量a在预编译阶段就已经做了类似于宏替换的工作,所以输出的是它的常量值,但是如果你进去调试就会发现变量a的地址与p地址相同,且p指向的地址的内容已经修改为了20,也就是说其实我们对这部分地址的内容已经做出了修改,所以
p输出的是20。但是在纯C的环境下,它并没有类似于宏替换的那一步,所以它输出的就是修改后的值。


41-60

41.关于C++的异常处理,下列说法正确的有?

A.函数指针与该指针所指的函数必须具有相同的noexcept异常说明
B.异常对象的初始化是通过拷贝初始化进行的
C.若析构函数中含有throw语句,而其声明中不包含noexcept(false)的显式声明,则编译无法通过
D.异常对象和异常声明的匹配规则中可以进行类型转换,遵循函数调用的形参、实参的转换规则

参考答案:B 解析: A项,函数指针与该指针所指的函数必须具有一致的noexcept异常说明,而非相同。特别的,隐式声明为noexcept(false)的函数指针可以指向noexcept(true)的函数,A错误。 C项,编译器并不会在编译时检查noexcept声明,编译可以通过,C错误。 D项,恰恰相反,在异常声明的匹配规则中,绝大多数类型转换都不被允许,除了以下3种例外:1)允许从非常量到常量的转换;2)允许派生类到基类的转换;3)数组转数组元素指针,函数转函数指针。除此之外,包括标准算术类型和类类型转换在内,其他的转换规则不能在异常catch匹配中使用,D错误。


42.给出以下定义:
Char x[]=“abc”;
Char y[]={‘a’,‘b’,‘c’};
以下描述正确的是()

A.数组X和数组Y等价
B.数组X和数组Y的大小相同
C.数组X的sizeof运算值大于数组Y的sizeof运算值
D.数组X的sizeof运算值小于数组Y的sizeof运算值

参考答案:C
解析:Char X[]等价于Char x[]={‘a’,‘b’,c’,‘\0’};


43.假设Qiniuome是一个类,执行下面语句之后,内存里创建了几个Qiniuome对象。

Qiniuome a();
Qiniuome b(2);
Qiniuome c[3];
Qiniuome &ra = b;
Qiniuome *pA = c;
Qiniuome*p = new Qiniuome(4);

参考答案:5.
解析:
CSomething a();//只是定义一个方法,方法返回一个CSomething对象
CSomething b(2);//增加1个对象
CSomething c[3];//对象数组,增加3个对象
CSomething //引用不增加对象
CSomething *pA=c;//地址赋值,不增加对象
CSomething *p=new CSomething;//在堆上构造一个对象,增加1个对象
所以最后一共有: 1+3+1 =5个对象。


end

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pikaqiu_04

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值