练习(四)

来源:互联网 发布:蓝月羽毛升级数据 编辑:程序博客网 时间:2024/05/17 09:10

1、以下函数中,和其他函数不属于一类的是____。

fwrite
putc
pwrite
putchar
getline
scanf
2、关于操作系统heap与stack说法中,正确的是()。

stack由编译器自动分配和释放,存放函数的参数值,局部变量,全局变量的值
heap一般由程序员分配和释放,若程序员不释放,可能会造成操作系统的内存泄露
stack由系统自动分配,无需程序员干涉,heap需要手动申请
heap与stack都会在初始大小空间用满时,系统自动增加其大小
3、a=3*5 , a*4; 最终a为60.是否正确?


正确

错误

4、已知职工记录描述如下,在Turbo C中,系统为变量w分配( )字节的空间。

struct worker

{  int no;

char name[20];

char sex;

union

{ int day;  int month;  int year;}birth;

} w;

  • 29
  • 20
  • 25
  • 6
5、已知表达式++a中的"++"是作为成员函数重载的运算符,则与++a等效的运算符函数调用形式为()
  • a.operator++()
  • a.operator++(0)
  • a.operator++(int)
  • operator++(a,0)

6、[单选题]

下面有关友元函数与成员函数的区别,描述错误的是?
  • 友元函数可以让本类和友元类对象调用
  • 友元函数和类的成员函数都可以访问类的私有成员变量或者是成员函数
  • 类的成员函数是属于类的,调用的时候是通过指针this调用的
  • 友元函数是有关键字friend修饰,调用的时候也是通过指针this调用的

7、下面哪种情况下,B不能隐式转换为A?

  • class B:public A{}
  • class A:public B{}
  • class B{operator A();}
  • class A{A(const B&);}

8、下列关于联合的描述中,错误的是?

  • 联合变量定义时不可初始化
  • 联合的成员是共址的
  • 联合的成员在某一个时刻只有当前的是有效的
  • 联合变量占有的内存空间是该联合变量中占有最大内存空间的成员在内存对齐时所需的存储空间

9、下列代码编译时会产生错误的是()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
struct Foo {
    Foo() {}
    Foo(int) {}
    voidfun() {}
};
int main(void) {
    Foo a(10);//语句1  
    a.fun();//语句2  
    Foo b();//语句3  
    b.fun();//语句4  
    return0;
    16.
}

  • 语句1
  • 语句2
  • 语句3
  • 语句4

10、对下面的程序段

 

 



编译运行后,程序输出结果是()

CB::f1() CC::f2()
CB::f1() CB::f2()
CB::f1() CA::f2()
CA::f1() CC::f2()
11、C++语言不能定义字符串变量。

T
F
12、

1
2
3
4
char* s="AAA"//1
printf("%s",s); //2
s[0]='B'//3
printf("%s",s); //4
哪一句会出错?
第1句
第2句
第3句
第4句
13、以下哪些对象可用于Windows进程间通信?

事件
临界区
互斥量
共享内存

14、
以下代码编译有错误,哪个选项能解决编译错误?
1
2
3
4
5
6
7
8
9
classA {
    public:
        intGetValue() const{
            vv = 1;
            returnvv;
         }
    private:
        intvv;
};

改变成员变量"vv"为"mutable int vv"
改变成员函数"GetValue"的声明,以使其不是const的
都不能修复编译错误
都可以修复编译错误
15、
在linux+gcc下,关于以下代码,正确的是()
1
2
3
4
5
6
7
8
9
10
11
std::string& test_str()
{
   std::string str="test";
   returnstr;
}
intmain()
{
   std::string& str_ref=test_str();
   std::cout<<str_ref<<std::endl;
   return0;
}

编译警告
返回局部变量的引用,运行时出现未知错误
正常编译且运行
把代码里的&都去掉之后,程序可以正常运行
16、以下正确的说法是(        ),在C语言中。

实参和与其对应的形参各占用独立的存储单元
实参和与其对应的形参共占用一个存储单元
只有当实参和与其对应的形象同名时才共占用存储单元
形参是虚拟的,不占用存储单元

17、int a[3];
a[0] = 0; a[1] = 1; a[2] = 2;
int *p, *q;
p = a;
q = &a[2];
 
则a[q - p] = ?
  • 0
  • 1
  • 2
  • 未知

18、

下面程序段的运行结果是()
1
2
3
4
5
6
7
int main(int argc, char *argv[])
{
    char*s ="abcdefg";
    s +=2;
    fprintf(stderr,"%d\n", s);
    return0;
}

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

    19、[单选题]

    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
    #include<iostream>
    using namespace std;
    class MyClass
    {
    public:
        MyClass(inti =0)
        {
            cout << i;
        }
        MyClass(constMyClass &x)
        {
            cout << 2;
        }
        MyClass &operator=(constMyClass &x)
        {
            cout << 3;
            return *this;
        }
        ~MyClass()
        {
            cout << 4;
        }
    };
    int main()
    {
        MyClass obj1(1), obj2(2);
        MyClass obj3 = obj1;
        return0;
    }
    运行时的输出结果是()
    • 11214444
    • 11314444
    • 122444
    • 123444

      20、执行"int x=1;int y=~x;"语句后,y的值为?

      • 1
      • 0
      • -1
      • -2

      21、

      不定项选择题]
      在linux编程中,以下哪个TCP的套接字选项与nagle算法的开启和关闭有关?
      • TCP_MAXSEG
      • TCP_NODELAY
      • TCP_SYNCNT
      • TCP_KEEPALIVE

      22、

      [不定项选择题]
      下列说明中 const char *ptr;ptr应该是()
      • 指向字符常量的指针;
      • 指向字符的常量指针;
      • 指向字符串常量的指针;
      • 指向字符串的常量指针;

      解析:

      1、

      常见文件系统 系统函数

      1. fcntl  文件控制  
      2. open  打开文件   
      3. creat  创建新文件  
      4. close  关闭文件描述字  
      5. read  读文件  
      6. write  写文件  
      7. readv  从文件读入数据到缓冲数组中  
      8. writev  将缓冲数组里的数据写入文件  
      9. pread 对文件随机读  
      10. pwrite  对文件随机写 
      2、

      在堆上分配内存
      可能许多人对内存分配上的“栈  stack ”和“堆  heap ”还不是很明白。包括一些科班出身的人也不明白这两个概念。简单的来讲, stack 上分配的内存系统自动释放,  heap 上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里。 stack 一般是静态分配内存,heap 上一般是动态分配内存。 
      由 malloc 系统函数分配的内存就是从堆上分配内存。从堆上分配的内存一定要自己释放。用 free 释放,不然就是术语——“内存泄露”(或是“内存漏洞”)——  Memory Leak 。于是,系统的可分配内存会随 malloc 越来越少,直到系统崩溃。还是来看看“栈内存”和“堆内存”的差别吧。
      3、

      赋值号右边是逗号表达式,因为赋值号的优先级很低,所以先计算右侧逗号表达式的值。效果近似于a=a*4

      4、

      2+20+1+2,分别是no的字节大小,name[20]的字节大小,sex的字节大小,然后是联合体birth的大小,联合体是个省内存的定义方法,里面的day month year被定义在一个2字节大小的空间中,它是day 还是month 还是year,完全取决于编程人员最后一次对它的引用.

      5、

      前置单目运算符重载为类的成员函数时,不需要显式说明参数,即函数没有形参。后置单目运算符重载为类的成员函数时,函数要带有一个整型形参。

      6、

      友元函数不是本类的成员,所以不能用this指针访问,一般用另一个类的成员函数来访问的。

      7、

      考点:类之间的隐式转换与上下行转换
      题目分析:
      (A)A是基类,B是派生类,在公有继承方式下,派生类对象/对象指针、对象引用可以赋值给基类的对象/对象指针/对象引用(这时发生隐式转换)。因为派生类中包含了基类中的所有信息。注意:将派生类对象赋值给基类对象,会造成截切问题(派生类中专属的数据和行为会被丢弃掉)
      (B)A是派生类,B是基类。基类对象对象指针、对象引用不能赋值给派生类的对象/ 对象指针、对象引用。原因同上。
      (C) operator A()是B类中的一个类型转换函数,可以将B类对象隐式转换成B类对象。
      (D)A(const B&)是A类的一个复制构造函数,可以将B类对象隐式转换成B类对象。
      8、

      1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。

      2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。

      union Test
      {
      inta;
      floatb;
      };
      Test test = {1};
      test变量的定义可以初始化,初始值的类型必须是union中第一个成员的类型。
       “联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。

      9、

      语句4编译会发生错误,若想调用类内的函数,则必须为一个类对象,而语句3中声明的Foo b()是声明了一个返回类型为Foo的一个函数,而并非建立了一个Foo类型的对象。因此,因为错误理解了语句3的声明而导致语句4的错误。

      10、

      答案是B。
      CA* pa = &c;这句话是父类指针指向子类对象,调用pa->f1()时,因为父类中的f1()是虚函数,所以将发生动态绑定,调用子类CB中的f1()函数,先输出CB::f1()
      在CB类的f1()函数中,调用非虚函数f2(),但因为其父类CA中的f2()函数并不是virtual函数,所以将调用CB类中的f2()函数,输出CB::f2()。如果将CA类中的f2()改成虚函数,那么将输出CC::f2();如果将CB类中的f2()改成虚函数,也将输出CC::f2(),这是满足动态绑定的。

      补充:

      为了支持c++的多态性,才用了动态绑定和静态绑定。理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误,需要理解四个名词:
      1、对象的静态类型:对象在声明时采用的类型。是在编译期确定的。
      2、对象的动态类型:目前所指对象的类型。是在运行期决定的。

      对象的动态类型可以更改,但是静态类型无法更改。关于对象的静态类型和动态类型,看一个示例:

      class B{}class C : public B{}class D : public B{}D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*C* pC = new C();pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C*

      3、静态绑定:绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期。

      4、动态绑定:绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期。

      class B{    void DoSomething();    virtual void vfun();}class C : public B{    void DoSomething();//首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导致名称遮掩;这里只是为了说明动态绑定和静态绑定才这样使用。    virtual void vfun();}class D : public B{    void DoSomething();    virtual void vfun();}D* pD = new D();B* pB = pD;

      让我们看一下,pD->DoSomething()和pB->DoSomething()调用的是同一个函数吗?
      不是的,虽然pD和pB都指向同一个对象。因为函数DoSomething是一个no-virtual函数,它是静态绑定的,也就是编译器会在编译期根据对象的静态类型来选择函数。pD的静态类型是D*,那么编译器在处理pD->DoSomething()的时候会将它指向D::DoSomething()。同理,pB的静态类型是B*,那pB->DoSomething()调用的就是B::DoSomething()。
       
      让我们再来看一下,pD->vfun()和pB->vfun()调用的是同一个函数吗?
      是的。因为vfun是一个虚函数,它动态绑定的,也就是说它绑定的是对象的动态类型,pB和pD虽然静态类型不同,但是他们同时指向一个对象,他们的动态类型是相同的,都是D*,所以,他们的调用的是同一个函数:D::vfun()。
       
      上面都是针对对象指针的情况,对于引用(reference)的情况同样适用。
       
      指针和引用的动态类型和静态类型可能会不一致,但是对象的动态类型和静态类型是一致的。
      D D;
      D.DoSomething()和D.vfun()永远调用的都是D::DoSomething()和D::vfun()。
       
      至于那些事动态绑定,那些事静态绑定,有篇文章总结的非常好:
      我总结了一句话:只有虚函数才使用的是动态绑定,其他的全部是静态绑定。目前我还没有发现不适用这句话的,如果有错误,希望你可以指出来。
       
      特别需要注意的地方
      当缺省参数和虚函数一起出现的时候情况有点复杂,极易出错。我们知道,虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的。

      class B{ virtual void vfun(int i = 10);}class D : public B{ virtual void vfun(int i = 20);}D* pD = new D();B* pB = pD;pD->vfun();pB->vfun();

      有上面的分析可知pD->vfun()和pB->vfun()调用都是函数D::vfun(),但是他们的缺省参数是多少?
      分析一下,缺省参数是静态绑定的,pD->vfun()时,pD的静态类型是D*,所以它的缺省参数应该是20;同理,pB->vfun()的缺省参数应该是10。编写代码验证了一下,正确。
      对于这个特性,估计没有人会喜欢。所以,永远记住:
      “绝不重新定义继承而来的缺省参数(Never redefine function’s inherited default parameters value.)”
       11、

      对于C与C++来说是没有字符串这种数据类型的,只是可以通过字符数组或者指向字符的指针又或者C++的标准库string来实现存储字符串,但是这并不能称作定义了字符串变量

      12、初始化 指针 时 ,所创建的 字符串常量 被定义为 只读!字符串常量不可以修改!

      13、

        共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。共享内存允许两个不相关的进程访问同一个逻辑内存。由于它并没有提供同步机制,所以我们通常需要用其他的机制来同步访问共享的内存。
         来张干货图吧:不仅仅windows支持的通信方式,其他系统也有。这里容易与同步混淆。

      14、1.mutable定义可变成员对象(即使在带有const的成员函数中也可改变成员对象的值) 2.c++中类的成员函数都有隐含的this指针,普通的非const成员函数中,this是一个指向类类型的const指针,可改变this所指向的值,但不可以改变this所保存的地址;在const成员函数中,不可改变this所指向的值,也不可改变this保存的地址。因此,本题当去掉const时,可以改变成员对象的值。

      15、引用返回的是局部变量本身,而不是复制一份再返回,所以结果难以预料;其次返回局部自动变量是可以的,只要不是地址或引用就可以,否则需要将变量声明成static类型。

      16、形参在编译时是不会分配存储容间,在调用时才在栈里分配

      17、这里q-p的实际运算是:(q的地址值-p的地址值)/sizeof(int),所以为2.

      18、

      stdout -- 标准输出设备 (printf("..")) 同 stdout。
      stderr -- 标准错误输出设备搜索
      两者默认向屏幕输出。
      但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕。

      19、

      关键是区分 浅/深拷贝操作 和 赋值操作:
      没有重载=之前:
      A a ;
      A b;
      a = b;
      这里是赋值操作。
      A a;
      A b = a; 
      这里是浅拷贝操作。

      重载 = 之后:
      A a ;
      A b;
      a = b;
      这里是深拷贝操作(当然这道题直接返回了,通常我们重载赋值运算符进行深拷贝操作)。
      A a;
      A b = a; 
      这里还是浅拷贝操作。

      所以 MyClass obj3 = obj1; 调用的是拷贝构造函数。

      如果写成 MyClass obj3; obj3 = obj1; 输出的结果就是 1203444

      20、

      假设int占2个字节,那么1的二进制表示是 0000 0001 ,~表示按位取反,则 0000 0001变为 1111 1110,在计算机中整数用补码形式表示,正数的补码是它本身, 负数的补码是原数值除符号位按位取反再加一,由补码求原数值也是按位取反再加一,那么 1111 1110   除符号位    按位取反再加一变成 1000 0010,即 -2。

      21、

      Nagle算法的规则:
      (1)如果包长度达到MSS,则允许发送;
      (2)如果该包含有FIN,则允许发送;
      (3)设置了TCP_NODELAY选项,则允许发送;
      (4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
      (5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

      Nagle算法只允许一个未被ACK的包存在于网络,它并不管包的大小,因此它事实上就是一个扩展的停-等协议,只不过它是基于包停-等的,而不是基于字节停-等的。Nagle算法完全由TCP协议的ACK机制决定,这会带来一些问题,比如如果对端ACK回复很快的话,Nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低。
      Nagle算法是silly window syndrome(SWS)预防算法的一个半集。SWS算法预防发送少量的数据,Nagle算法是其在发送方的实现,而接收方要做的是不要通告缓冲空间的很小增长,不通知小窗口,除非缓冲区空间有显著的增长。这里显著的增长定义为完全大小的段(MSS)或增长到大于最大窗口的一半。
      注意:BSD的实现是允许在空闲链接上发送大的写操作剩下的最后的小段,也就是说,当超过1个MSS数据发送时,内核先依次发送完n个MSS的数据包,然后再发送尾部的小数据包,其间不再延时等待。(假设网络不阻塞且接收窗口足够大)
      举个例子,比如之前的blog中的实验,一开始client端调用socket的write操作将一个int型数据(称为A块)写入到网络中,由于此时连接是空闲的(也就是说还没有未被确认的小段),因此这个int型数据会被马上发送到server端,接着,client端又调用write操作写入‘\r\n’(简称B块),这个时候,A块的ACK没有返回,所以可以认为已经存在了一个未被确认的小段,所以B块没有立即被发送,一直等待A块的ACK收到(大概40ms之后),B块才被发送。整个过程如图所示:
      这里还隐藏了一个问题,就是A块数据的ACK为什么40ms之后才收到?这是因为TCP/IP中不仅仅有nagle算法,还有一个TCP确认延迟机制 。当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。在我之前的时间中,t大概就是40ms。这就解释了为什么'\r\n'(B块)总是在A块之后40ms才发出。
      当然,TCP确认延迟40ms并不是一直不变的,TCP连接的延迟确认时间一般初始化为最小值40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。另外可以通过设置TCP_QUICKACK选项来取消确认延迟。

      22、


      常量指针。

      常量是形容词,指针是名词,以指针为中心的一个偏正结构短语。这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针(变量)。

      指针指向的对象是常量,那么这个对象不能被更改。















      原创粉丝点击