练习(一)

1、

在32位编译器上,设有定义

1
char  * strl =  "Hello" ,str2[ ] =  "Hello" ;

则以下语句

1
printf( "%d %d" ,sizeof(str),sizeof(str2));
的输出结果是()
2、 下述静态数据成员的特征中,(       )是错误的。
A.定义静态数据成员时前边要加修饰符 static
B.静态数据成员要在类体外进行初始化
C.引用静态数据成员时,要在静态数据成员名前加<类名>和作用域运算符
D.静态数据成员不是所有对象所共用的。
3.
下列 描述中,() 是抽象类特有的

A.不可以声明虚函数
B.不可以定义友元函数
C.不可以进行构造函数重载
D.不可以实例化
4.
下列给定程序中已建立一个带头结点的单向链表,链表中各节点按节点数据域中的数据递增有序链接。函数fun的功能是:把形参x的值放入一个新节点并插入列表中使插入后各节点数据域中的数据仍保持递增有序。 
请在程序的下画线处填入正确的内容并将下画线删除,使程序得出正确的结果。
试题程序。
#include<stdio.h>
#include<stdlib.h>
#define N  8
typedef struct list
{
int data;
struct list *next;
} SLIST;
void fun(SLIST *h, int x)
{
SLIST *p, *q, *s;
s = (SLIST *)malloc(sizeof(SLIST));
s->data =  1  ;
q = h;
p = h->next;
while (p != NULL && x > p->data)
{
q =  2  ;
p = p->next;
}
s->next = p;
/********** found **********/
q->next =  3  ;
}
SLIST *crealist(int *a)
{
SLIST *h, *p, *q; int i;
h = p = (SLIST *)malloc(sizeof(SLIST));
for (i = 0; i < N; i++)
{
q = (SLIST *)malloc(sizeof(SLIST));
q->data = a[i]; p->next = q; p = q;
}
p->next = 0;
return h;
}
void outlist(SLIST *h)
{
SLIST *p;
p = h->next;
if (p == NULL)
printf("\nThe list is NULL!\n");
else
{
printf("\nHead");
do
{
printf("->%d", p->data);
p = p->next;
}
while (p != NULL);
printf("NULL");
printf("->End\n");
}
}
main( )
{
SLIST *head; int x;
int a[N] = (11, 12, 15, 18, 19, 22, 25, 29);
head = creatlist(a);
printf("\nThe list before inserting:\n");
oulist(head);
printf("\nEnter a number: "); scanf("%d", &x);
fun(head, x);
printf("\nThe list after intserting:\n");
outlist(head);
}
5、


下列说法正确的是:

内联函数在运行时是将该函数的目标代码插入每个调用该函数的地方
内联函数在编译时是将该函数的目标代码插入每个调用该函数的地方
类的内联函数必须在类体内定义
类的内联函数必须在类体外通过关键字inline定义
6、
说明一下++p 与 p++ 的区别。

没有区别
++p更好一些
p++更好一些
和编译器有关
7、


已知集合A和B的元素分别用不含头结点的单链表存储,函数difference( )用于求解集合A与B的差集,并将结果保存在集合A的单链表中。例如,若集合A={5,10,20,15,25,30},集合B={5,15,35,25},完成计算后A={10,20,30}。

链表结点的结构类型定义如下:
struct node  
{  
int elem;  
node* next;  
};  
 
void difference(node** LA , node* LB)  
{  
node *pa , *pb , *pre , *q;  
pre = NULL;  
(1) //1   
while(pa)  {  
pb = LB;  
   while(  2  )                //2   
   pb = pb->next;  
   if ( 3    )                //3   
   {  
    if(!pre)  
        *LA = ( 4  )   ;     //4   
     else  
            ( 5 )= pa->next;     //5
     q = pa;  
     pa = pa->next;  
     free(q);  
   }  
    else  {  
            ( 6 );             //6   
           pa = pa->next;  
    }  
}  
}  


8.

若有以下程序

1
2
3
4
5
6
7
8
9
#include <stdio. h>
main( )
     int  a =  0 ,b =  0 ,c =  0 ,d; 
     c = (a + = b,,b + = a);     / * 第 4 行 * /
     d = c;        / * 第 5 行 * /
     ;         / * 第 6 行 * /
     ;printf( "%d,%d,%d\n" ,a,b,c);/ * 第 7 行 * /
}
编译时出现错误,你认为出错的是
第4行
第5行
第6行
第7行
9.

下列对函数double add(int a , int b)进行重载,正确的是()
int add(int a ,int b ,int c)
int add(double a , double b)
double add(double a , double b)
int add(int a , int b)
10.
下面函数的功能是
1
2
3
4
5
6
int fun (char *s)
{
     char *p=s;
     while(*p++);
     return p-s-1;
}
计算字符串的位(bit)数
复制一个字符串
求字符串的长度
求字符串存放的位置
11.

假设A为抽象类,下列声明( )是正确的
A fun(int);
A*p;
int fun(A);
A obj;
12.
以下描述不正确的有

try块不可以省略
可以使用多重catch块
finally块可以省略
catch块和finally块可以同时省略
13、以下描述正确的是?

虚函数是可以内联的,可以减少函数调用的开销提高效率
类里面可以同时存在函数名和参数都一样的虚函数和静态函数
父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
以上都不对
14.
以下哪个选项一定可以将flag的第二个bit置0

flag&=~2
flag|=2
flag^=2
flag>>=2
15.
派生类的构造函数的初始化列表中,不能包含(       )
基类的构造函数
派生类中子对象的初始化
基类的子对象初始化
派生类中一般数据成员的初始化
16.
下列哪个用法哪个是错误的()
int *a;
extern const int array[256];
const int &ra;
typedef void (*FUN)();
17.
下面这段代码会打印出什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class A
{
public :
     A()
     {
         printf( "A " );
     }
     /*virtual*/
     ~A()
     {
         printf( "deA " );
     }
};
 
class B
{
public :
     B()
     {
         printf( "B " );
     }
     ~B()
     {
         printf( "deB " );
     }
};
 
class C:  public A,  public B
{
public :
     C()
     {
         printf( "C " );
     }
     ~C()
     {
         printf( "deC " );
     }
};
int main()
{
     A *a =  new C();
     delete a;
     return 0 ;
}

A B C deA
C A B deA
A B C deC
C A B deC

18.
设有以下定义程序 ; 则以下合法的调用语句是()

obj3.show3();
obj2.show2();
obj1.show1();
obj3.show1();
19.
下面选项中关于   "   文件指针   "   概念的叙述正确的是()
文件指针是程序中用FILE定义的指针变量
文件指针就是文件位置指针,表示当前读写数据的位置
文件指针指向文件在计算机中的存储位置
把文件指针传给fscanf函数,就可以向文本文件中写入任意的字符
20.
求输出结果 
1
2
3
int a[ 2 ][ 2 ][ 3 ]= { {{ 1 , 2 , 3 },{ 4 , 5 , 6 }},{{ 7 , 8 , 9 },{ 10 , 11 , 12 }}};
int *ptr=( int *)(&a+ 1 );
printf(“%d %d”, *( int *)(a+ 1 ), *(ptr- 1 ));
7 12
1 6
1 3
7 9














答案:
1、4 , 6
sizeof(str1)=4,因为str1是一个指针变量,在32位编译器中指针是4字节;
sizeof(str2)=6,str2字符数组中有5个字符,再加一个结束符'\0',所以共占6个字节;
2、D
类的静态成员与类本身直接相关,而不是与类的各个对象保持关联。在成员的声明之前加上关键字static使得其与类关联在一起,和其他成员一样,静态成员可以是public的或private。
我们使用作用域运算符直接访问静态成员。
通常情况下,类的静态成员不应该在类的内部初始化,然而,我们可以为静态成员提供const整数类型的类内初始值,必须是常量表达值。
3.D
一、纯虚函数定义.

     纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0” 二、引入原因: 1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。 2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。      为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。 三、相似概念: 1、多态性     指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。     a.编译时多态性: 通过函数重载和运算符重载来实现的。     b 运行时多态性:通过继承和虚函数来实现的。 2、虚函数     虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载     纯虚函数的声明有着特殊的语法格式:virtual 返回值类型成员函数名(参数表)=0;

 请注意,纯虚函数应该只有声明,没有具体的定义,即使给出了纯虚函数的定义也会被编译器忽略。

3、抽象类

包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。   在C++中,我们可以把只能用于被继承而不能直接创建对象的类设置为抽象类(Abstract Class)。

之所以要存在抽象类,最主要是因为它具有不确定因素。我们把那些类中的确存在,但是在父类中无法确定具体实现的成员函数称为纯虚函数。纯虚函数是一种特殊的虚函数,它只有声明,没有具体的定义。抽象类中至少存在一个纯虚函数;存在纯虚函数的类一定是抽象类。存在纯虚函数是成为抽象类的充要条件
抽象类是不完整的,它只能用作基类。在 面向对象方法中,抽象类主要用来进行类型隐藏和充当全局变量的角色。
抽象类具有以下特性:
  • 抽象类不能实例化。
  • 抽象类可以包含抽象方法和抽象访问器。
  • 不能用 sealed 修饰符修饰抽象类,因为这两个修饰符的含义是相反的。 采用 sealed 修饰符的类无法继承,而 abstract 修饰符要求对类进行继承。
  • 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实际实现。

4.
1 x
2 p->data
3 q
说明:
1.新建了一个结点s,那么把x放入s的data域中. 所以就是s->next = x;
2.记住,单链表中插入一个结点一定要知道插入结点处的前驱结点.所以q,p实际上是构造了一个前(q指针),一个后(p指针)的两个相邻指针,所以 q = p; p = p->next;  但是因为在前面已经说明了q是指向头结点,而p是指向第一个数据结点,那么此时其实已经使得q,p构成了一前一后的两个相邻指针,所以q也可以按照自己的步伐一步步的走,即q = q->next;
3.单链表结点插入操作
5.
内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。
内联函数从 源代码 层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用 函数体 替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看 编译器 对该函数定义的具体处理。 
正确答案选B,C和D都不完全,如果将C和D中的“必须”换成“可以”,那么C和D也是对的。
6.
指针++和i++是类似的。
因为i++在计算时,会用到中间变量存储,会占用更多的内存和时间。所以++i更好。
7、
参考答案 
(1) pa = *LA;
(2) pb && pa->elem != pb->elem
(3) pb
(4) pa->next
(5) pre->next
(6) pre = pa
#include<stdio.h>
 
struct node{
     int elem;
     struct node* next;
};
 
/*
     本题的解法思路较简单:
     因为要求集合A和集合B的差集(A-B),结果保存在集合A中.
     所以我们取出集合A中每一个元素,然后在集合B中寻找(代码22行所实现) 找到即删除此节点 否则保留
     此时while循环跳出只有两种情况,pb为NULL或者 pa->elem==pb->elem
     当pb不为null时,即找出集合A和集合B的公有元素,此时要删除这个元素
         pre(实现删除节点之后的链接)
         当pre为NULL时,说明是首次找到A和B的公有元素,此时 *LA指向pa->next 所以*LA仍然是头结点
         当pre不为NULL时, pre指向pa->next,顺利实现删除节点的链接
*/
 
 
void difference(node** LA,node* LB){
     node*pa,*pb,*pre,*q;
     pre=NULL;
     pa=*LA; /*LA是指向指针的指针,pa指向集合的元素*/
     while (pa){
         pb=LB; /*pb指向集合B的元素*/
         while (pb && pa->elem!=pb->elem)  /*在链表LB中寻找与pa所指元素相等的节点*/
             pb=pb->next;
         if (pb){  /*pa所指元素与pb所指元素相等*/
             if (!pre){
                 *LA=pa->next;
             } else {
                 pre->next=pa->next;
             }
             q=pa; /*求差集 所以要删除pa节点*/
             pa=pa->next;
             free (q);
         } else {
             pre=pa;
             pa=pa->next;
         }
     }
}
8.
逗号表达式中间不能为空,必须要有表达式。
9.
在C++中,函数的重载取决于函数的特征标即函数的参数列表。同名的函数,特征标不一样则函数不一样,A、B、C 的参数列表与题目给出的特征标数量或类型不一样,因此正确答案为A、B、C   
10、

int fun (char *s)
{
char *p=s;/*将S的地址给p;
while(*p++);/*没有遇到/0的时候p一直增加
return p-s-1;/*原始地址与增加后的地址的差减掉/0的长度
}
11.
抽象类不能实例化, 因而D选项明显不正确。
抽象类不能参数类型和函数返回类型,因而A和C不对
抽象类可以用作指针类型,因而B选项正确
12、
答案是d. try块是捕捉异常用的,用来做防护的,如果有异常发生将会在catch中捕获并加以处理,finally中是用来做最后的回收情况的必然会执行,而catch块不一定执行,catch有可能会有多个因为这样处理不同异常情况。
13.
对于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()
14.
负数在计算机中的存储方式
以补码的形式存储:
正数的补码就是 其本身
负数的补码是取绝对值后,再取反后,再加1
例如:
-1 绝对值的二进制形式为 0000 0001
                              取反  1111 1110
                              加1   1111 1111
因此在计算机中的存储为1111 1111

-2  为 1111 1110;

~2 取反运算符
  2 的 二进制表示形式为 0000 0010
                         取反为 1111 1101
即是-3在计算机中的存储形式;
15.

构造函数是不可继承的。因此,派生类的构造函数必须通过调用基类的构造函数初始化基类成员,不能够在派生类初始化列表直接初始化基类的成员,“越级初始化”。派生类的构造函数的一般格式为:

派生类名(形参表):基类名1(形参表1),基类名2(形参表2)···

{···}

注意事项:

(1)在创建派生类对象时,先调用基类的构造函数,然后调用派生类的构造函数;撤销对象时,析构函数被调用的顺序则相反。

(2)若派生类中包含对象成员,则派生类的构造函数初始化成员列表中既要列出基类的构造函数也要列出对象的构造函数。派生类定义对象时,先调用基类的构造函数,再调用对象的构造函数,最后调用派生类的构造函数。


16.

加上const修饰符,这个值就不可改了,
所以必须在初始化的时候给值,和加不加引用无关。
引用本身就应该初始化,加上const时,更应该初始化了
typedef void (*FUN)();
定义FUN为一个函数指针,指向一个函数,该函数返回值为void,参数为空
17.如果按题中所说 加入virtual,那么输出的顺序是ABC deC deB deA。由于析构函数是虚函数,动态调用,那么会调用C的析构函数,由于C继承与A和B,所以先调用A B的析构,最后调用自己的。
如果A的析构函数不是虚函数,那么只会调用A的析构函数。
18.

19.文件指针指向的是一块内存区域,这块区域存储着打开的文件的相关信息,包括文件读取指针当前位置、文件读取缓冲区大小等信息,并不是指向文件的。fscanf是从文件中格式化读取,fprintf才是向文件中格式化写入。
20.

答案:A

*(int*)(a+1) 指向数组 a[2] 的第二个元素中的第一个,也就是内部第二层大括号的第一个元素

*(ptr-1)整个数组的最后一个元素,因为 (int *)(&a+1); 指向整个数组的下一个位置

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HySmiley

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

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

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

打赏作者

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

抵扣说明:

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

余额充值