C/C++琐碎知识归纳之一

1.内存泄露 2.volatile 3.前后++与小括号的关系 4.派生类中基类构造函数、成员中其他类对象的构造函数、派生类自己的构造函数执行顺序 5.构造函数和析构函数能否为虚函数 6.字符变量赋值 7.UTF-16和UTF-8 8.类中实例化其他类对象时,其他类构造函数的顺序 9.异或^:满足交换律和结合律 10.关系代数中五种基本运算 11.重复抽样与不重复抽样的抽样平均误差大小12.关于浮点数位操作和逻辑操作 13.拷贝函数的构造函数 14.this指针问题 15.read()不是库函数,是系统调用 16.分支限界法 是对回溯法做出优化 17.枚举变量
1.内存泄露
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
2.volatile
volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.
简单地说就是防止编译器对代码进行优化.比如如下程序:

XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;

对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(产生四条代码)。
3.前后++与小括号的关系

int a=3,b=5;
printf("%d",(a++)*++b);/*或者是printf("%d",a++*++b);   结果都是一样的,前后自增不会受小括号的影响*/

4.派生类中基类构造函数、成员中其他类对象的构造函数、派生类自己的构造函数执行顺序:先执行基类的构造函数(如果基类中有虚基类,则先执行虚基类的构造函数,其他基类则按照派生类声明的先后顺序执行),然后是成员中其他类对象的构造函数,最后是派生类自己的构造函数
5.构造函数和析构函数能否为虚函数
构造函数不可以为虚函数,而析构函数可以为虚函数,原因如下:
析构函数不可为虚函数的原因:虚函数的调用,需要虚函数表指针,而虚函数表指针是存放在对象的内存空间的,如果构造函数为虚函数,此时对象还没有被创建,何谈对象内存空间的分配,因此无法调用虚函数——虚构造函数。
析构函数可以为函数,而且一般推荐使用虚函数,原因如下:如果采用基类的指针或引用方式调用子类时,如果不将基类的析构函数设置为虚函数,容易造成内存泄露,举例说明:

A *p=new B;//B是继承A的派生类
delete p;

I.如果基类A的析构函数不设置为虚函数,那么delete p时,仅会调用A的析构函数,释放B中A的不分,而B新多出来的部分则不会被释放,这样就可能会造成内存泄露;
II.如果将基类A的析构函数设置为虚函数,那么在delete p时,会先调用基类B的析构函数,然后调用基类A的析构函数,这样就不会出什么问题。这样等同于如下代码,也是先调用派生类B的析构函数,然后调用A的析构函数:

B *p=new B;
delete p;

6.字符变量赋值

char a='\82';
printf("a=%c",a);

输出是a=2,为什么是2呢?首先,\0oo:八进制值(o表示一个八进制数),显然这里不是八进制数,\xhh:十六进制值(h表示一个十六进制数字),这里也不是,so,\82只能代表三个字符 \、8、2,又因为赋值是从右往左进行的,最先扫描到的就是2,所以a的值就是2,输出为a=2;
7.UTF-16和UTF-8
UTF-16 固定表示两个字节表示一个字符,不管是字母还是汉字; UTF-8 使用 1- 3 个字节表示一个字符,根据保存的内容不同而不同。如果保存的汉字多,使用 UTF-16 占用字符数双倍的空间,使用 UTF-8 占用字符数三倍的空间;如果保存的英文字母多,使用 UTF-16 使用字符数双倍的空间,使用 UTF-8 使用字符数相同的空间。
更详尽的介绍见:http://www.cnblogs.com/wpcockroach/p/3907324.html
8.类中实例化其他类对象时,其他类构造函数的顺序:先执行该类的构造函数,然后调用其他类的构造函数,调用顺序是按照其他类定义对象的先后顺序,而不是传参数的顺序,其他实例如果需要传参数初始化,则该类的构造函数必须进行显示的对对象进行初始化,如下:

class Printer{
    public:
        Printer(std::string name) {std::cout << name;}
};
class Container{
    public:
        Container() : b("b"), a("a") {}
    Printer a;
    Printer b;
};
int main(){
    Container c;
    return 0;
}

输出一直都是:ab!
9.异或^:满足交换律和结合律
例如:x^(x^y)=x^x^y=y,y^(x^y)=y^x^y=y^y^x=x。
10.关系代数中五种基本运算
五种基本关系代数运算:并(∪)、差(—)、笛卡尔积(x)、投影(σ)、选择(π);
并(∪):两个关系需要有相同的关系模式,并的对象是元祖,由两个关系所有元祖构成,R∪S={t|t∈R∪t∈S}
差(—):同样,两个关系有相同的模式,R和S的差是由属于R,但不属于S的元祖构成的集合。R—S={t|t属于R,但不属于S};
笛卡尔积(x):对两个关系R和S进行操作,产生的关系中,元祖个数为两个关系中元祖个数之积,R×S≡{t| t=< tr,ts>,tr∈R,ts ∈S} ;
投影(σ):对关系进行垂直分割,消去某些列,并重新安排列的顺序;
选择(π):根据某些条件关系,作水平分割,即选择符合条件的元祖。
11.重复抽样与不重复抽样的抽样平均误差大小
这里写图片描述
12.关于浮点数位操作和逻辑操作
浮点数不允许直接进行移位,但可以通过间接的进行,例如,将float型数据取地址后,强制转化为整型(int/unsigned int/long等)送给该类型指针,然后用取值操作符(*)将值赋给对应的整型变量,下面就能对该整型变量进行位操作了。
【注】对浮点型数据移位意义不大,因为浮点型数据在内存中分三部分表示:符号位(1)、阶数(8)、尾数部分(23),这里给出的是float型在32位操作系统的存储方式,进行左右移位操作时,移位后的数据,与原始数据没有任何意义。
逻辑运算符:非(!)、与(&&)、或(||),操作对象可以是任何类型数据
13.拷贝函数的构造函数
拷贝构造函数的形参不限制为const,但是必须是一个引用,以传地址方式传递参数,否则导致拷贝构造函数无穷的递归下去,指针也不行,本质还是传值。
14.this指针问题
this指针是一个const修饰的常指针,不能够被修改。
如果有一个类MyClass如下:

~MyClass()
{
delete this;
this=NULL;
}

上面的代码无法通过编译,原因就是,delete this错误,this指针不能够被修改;假设上面代码能通过编译,则delete运算符被执行时,首先会调用析构函数,然后再释放内存,这样会再次调用~MyClass,依然发生错误。
15.read()不是库函数,是系统调用,作用是读文件(Linux中的一切设备都看做文件)
函数原型:
Ssize_t read(int filedes, void *buf, size_t nbytes);
Returns:number of bytes read, 0 if end of file, -1 on error
如果read系统调用成功,则将返回读取到的字节数;如果遇到了文件尾EOF,则返回0。
16.分支限界法 是对回溯法做出优化。 feasible(S,x)是剪枝函数。
S=S+{x}; C=C-{x};是回溯(分支)过程

Method(C)
{S={};
  while(not solution(S))
   { x=select(C);
      if feasible(S,x)
     S=S+{x};
     C=C-{x};
   }
 return S;
}

17.枚举变量是全局变量的情况下,枚举值的缺省值是0,不是枚举的第一个值。其他情况,其值是不定的,而且不限定于所列出的枚举值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值