牛客网错题总结

来源:互联网 发布:淘宝偷图会有什么后果 编辑:程序博客网 时间:2024/06/14 06:55


错题分析:A:虽然能得到想要的结果,但会造成内存泄露, 指针a脱离该函数后,不在能被调用;B:返回局部变量,出错;D:与B类似




解析:

其中全局变量和静态局部变量时从 静态存储区中划分的空间,
二者的区别在于作用域的不同,全局变量作用域大于静态局部变量(只用于声明它的函数中),
而之所以是先释放 D 在释放 C的原因是, 程序中首先调用的是 C的构造函数,然后调用的是 D 的构造函数,析构函数的调用与构造函数的调用顺序刚好相反。
局部变量A 是通过 new 从系统的堆空间中分配的,程序运行结束之后,系统是不会自动回收分配给它的空间的,需要程序员手动调用 delete 来释放。
局部变量 B 对象的空间来自于系统的栈空间,在该方法执行结束就会由系统自动通过调用析构方法将其空间释放。
之所以是 先 A  后 B 是因为,B 是在函数执行到 结尾 "}" 的时候才调用析构函数, 而语句 delete a ; 位于函数结尾 "}" 之前。







解析:122444

 【拷贝构造函数】,又称复制构造函数,是一种特殊的构造函数
在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):
1) 一个对象作为函数参数,以值传递的方式传入函数体;
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
3) 一个对象用于给另外一个对象进行初始化(常称为赋值 初始化);

【析构函数】析构函数(destructor) 与 构造函数 相反,当对象脱离其 作用域 时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

 MyClass obj3 = obj1;
调用复制构造函数
这个对应MyClass(const MyClass &x)
    {
        cout << 2;
    }
而非赋值符号的重写 “(重载 = 之后: A a ; A b; a = b;  这样子先声明才是赋值
  MyClass &operator=(const MyClass &x)
    {
        cout << 3;
        return *this;
    } 








选C
1.这个叫柔性数组,它的作用跟指针差不多,但是指针占空间,而它不占空间,这就意味着可以节省空间。
2.该数组的内存地址就和它后面的元素地址相同,意味着无需初始化,数组名就是后面元素的地址,直接就能当指针使用。例如,制作动态buffer,可以这样分配空间malloc(sizeof(structXXX) + buff_len); 直接就把buffer的结构体和缓冲区一块分配了。这样使用释放一次即可,如果使用指针,则需要释放两次。
3.也可以写成data[1]或data[],是考虑到可移植性的原因,因为有些编译器不支持0数组。




选择B:
程序运行的过程:
B*p = new B;//调用B的构造函数,此时发现继承自A,所以先调A的构造函数,结束后,再调B的构造函数。
 p->test();//调用test()函数,此时需要调用func()函数,因为缺省参数是静态绑定的,“绝不重新定义继承而来的缺省参数,所以打印B->1



函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用传递。以下讨论称调用其他函数的函数为主调函数,被调用的函数为被调函数。 
  值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。 
  引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量








此题参考链接:http://www.nowcoder.com/questionTerminal/62984d298f9f4d7d87d7236e0a5a93fc






char类型的取值范围是-128~127,unsigned char的取值范围是0~256
这里a[0]=256,出现了正溢出,将其转换到取值范围内就是0,即a[0]=0;
同理,a[1]=-1, a[2]=-2, a[3]=-3,在C语言标准里面,用补码表示有符号数,故其在计算机中的表示形式如下:
a[0]=0,     0000 0000
a[1]=-1,    1111 1111
a[2]=-2,    1111 1110
a[3]=-3,    1111 1101
short是2字节(a[0]和a[1]),由于80X86是小端模式,即数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,在本例中,a[0]中存放的是b的低位,a[1]中存放的是b的高位,即b的二进制表示是:1111 1111 0000 0000,表示-256



A: 2的平方根                                   B: 10的30次方                          C: 0.1                                 D: 0.5


分析:

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型必然也会产生舍入误差,举个例子,11101若写成1.11x2^4,这样就回有舍入误差了,但是11100写成1.11x2^4不会存舍入误差,所以存不存在舍入误差取决于从其第一个不为0到最后一个不为0的位之间的位数是否能全部存储,B的值估计是在2^90~2^100次方之见,至少需要90位才能将其按二进制存储,但是因为 B = 2^30*5^30,说明其二进制表示中,后30位全为0,从第一个不为0到其最后一个不为0的位,共至少有90-30=60位,而根据标准来说,8字节的double类型只有52位来存储尾数


链接:http://www.nowcoder.com/questionTerminal/d12c2556b4614d8b87a7b64d0d0c24bb








出处:http://blog.sina.com.cn/s/blog_4b4cf2af0100ywgv.html
在类的成员函数中能不能调用delete this?答案是肯定的,能调用,而且很多老一点的库都有这种代码。假设这个成员函数名字叫release,而delete this就在这个release方法中被调用,那么这个对象在调用release方法后,还能进行其他操作,如调用该对象的其他方法么?答案仍然是肯定 的,调用release之后还能调用其他的方法,但是有个前提:被调用的方法不涉及这个对象的数据成员和虚函数。说到这里,相信大家都能明白为什么会这样 了。

根本原因在于delete操作符的功能和类对象的内存模型。当一个类对象声明时,系统会为其分配内存空间。在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。当 调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。

为什么是不可预期的问题?delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个进程。照这个逻辑来看,应该发生指针错误无访问权限之类的令系统崩溃的问题才对啊?这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是一串很长的未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。


大致明白在成员函数中调用delete this会发生什么之后,再来看看另一个问题,如果在类的析构函数中调用delete this,会发生什么?实验告诉我们,会导致堆栈溢出。原因很简单,delete的本质是“为将被释放的内存调用一个或多个析构函数,然后,释放内存” (来自effective c++)。显然,delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃








实型常量 - 实数 - 浮点数


实型常量又称实数或浮点数。在C语言中可以用两种形式表示一个实型常量。
小数形式
        小数形式是由数字和小数点组成的一种实数表示形式,例如0.123、.123、123.、0.0等都是合法的实型常量。
        注意:小数形式表示的实型常量必须要有小数点
指数形式
        这种形式类似数学中的指数形式。在数学中,一个可以用幂的形式来表示,如2.3026可以表示为0.23026×10^1 2.3026×10^0 23.026×10^-1等形式。在C语言中,则以“e”或“E”后跟一个整数来表示以“10”为底数的幂数。2.3026可以表示为0.23026E1、2.3026e0、23.026e-1。C语言语法规定,字母e或E之前必须要有数字,且e或E后面的指数必须为整数。如e3、5e3.6、.e、e等都是非法的指数形式。注意:在字母e或E的前后以及数字之间不得插入空格。
        程序运行的过程中,其值不能被改变的量称为常量。常量有不同类型,其中12、0、-5为整型常量。'a''b'为字符常量。而4.6、-8.7则为实型常量。

一个实型常量可以赋给一个 float 型、double 型或 long double 变量。根据变量的类型截取实型常量中相应的有效位数字。



有关虚函数

(1)在构造函数和析构函数中调用虚函数,均不能实现多态由于类的构造次序是由基类到派生类,所以在构造函数中调用虚函数,继承类没有初始化,这个虚函数不会呈现出多态; 相反,类的析构是从派生类到基类,当调用继承层次中某一层次的类的析构函数时往往意味着其派生类部分已经析构掉,所以也不会呈现出多态

(2)虚函数可以是inline

(3)静态函数不可以是虚函数




链接:http://www.nowcoder.com/questionTerminal/f19c393eb6024e08b2f17f2c99c502c3




c语言中static的语义
1.static变量:


1).局部
a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。
b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的


2).全局
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
2.static函数(也叫内部函数)
只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)

》》》http://blog.chinaunix.net/uid-21702630-id-205952.html




这里主要是TCP三次握手期间的发送序号和确认序号。
TCP第一次握手期间:客户机向服务器发送请求报文段,发送序号为x
TCP第二次握手期间:服务器向客户机发送请求+确认报文段,发送序号为y,确认报文段为x+1
TCP第三次握手期间:客户机向服务器发送确认报文段,发送序号为x+1,确认序号为y+1
这里第三次握手报文的发送序列号为1000,确认序列号为2000,可以退出第二次握手发送序号为1999,确认序号为1000.




指针p必须指向一个已存在的对象,才能输出值





抽象类:至少有一个方法是抽象方法

接口:类中方法全部是抽象方法

含有虚函数(抽象方法)的类即为抽象类;
1
接口中所有的方法均为抽象方法,即它和纯虚类意思相同







traits是C++的自动类型判断。
出发点:因为C++没有反射的机制。所以利用traits来完成。
大量使用场景:STL(STL中大量使用traits来区分类别。注释POD标量类型和类类型的构造函数等)
机制:
1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename T> 
//泛化
struct is_void
static const bool value = false; };
template <> 
//特化
struct is_void<void>
static const bool value = true; };
 
intmain(){
    std::cout<<is_void<int>::value;
    std::cout<<is_void<void>::value;
}
根据模板的自动类型推导。在调用void的时候会使用特化版本。而其他类型呢?对,使用泛化版本。
这样就巧妙的区分了不同的类型。这就是traits的基本原理。
C++11中提供了大量的traits,可参考http://www.cplusplus.com/reference/type_traits/




1、概述:

   模板(Template)是一种强大的C++软件复用特性,通常有两种形式:函数模板和类模板。函数模板针对仅参数类型不同的函数(答案C ok);类模板针对仅数据成员和成员函数类型不同的类(答案D ok)。函数模板和类模板可以是程序员只需制定一个单独的代码段,就可表示一整套称为函数模板特化的相关(重载)函数或是表示一整套称为类模板特化的相关的类。这种技术称为泛型程序设计(generic programming)。

使用模板的好处在于,可以使程序员编写与类型无关的代码。

-----------------
模板是一个类家族的抽象,它只是对类的描述,编译程序不为类模板(包括成员函数定义)创建程序代码,但是通过对类模板的实例化可以生成一个具体的类以及该具体类的对象。
与函数模板不同的是:函数模板的实例化是由编译程序在处理函数调用时自动完成的(答案A正确),而类模板的实例化必须由程序员在程序中显式地指定(答案B正确)





地址偏移量=逻辑地址%页面大小(1024)=0A1F(H)(2591)%1024=543
页号=逻辑地址/页面大小=2591/1024=2
 查页表得到块号为3,
故物理地址=3*1024+543=3615=0E1F(H)









0 0
原创粉丝点击