C/C++拾遗

枚举是一个常量整型的列表,如enum boolean {NO, YES};则,第一个值为0,第二个值为1


类型转换:

自动转换:将“比较窄的”操作数转换为“比较宽的”操作数,且不丢失信息。

当把较长的整数转换为较短的整数或char型时,超出的高位部分将被丢弃。

强制类型转换只是生成一个指定类型的n值,n本身并没有改变,如sqrt((double)n);

浮点数在内存中的表示:http://www.cnblogs.com/xkfz007/archive/2012/02/27/2370357.html

浮点数二进制与十进制的转换:http://www.cnblogs.com/xkfz007/articles/2590472.html(X86使用的是反字节序,printf对于类型不匹配的处理)


 printf函数:

  x,d等等这些都是以int形式输出,若是要以浮点数形式输出,则需要%f,%e,%g等等

  printf函数参数的入栈是从右往左,比如下面这个程序:

int main(int argc, char *argv[])
{
    char* a[] = {"hello","the","world"};
    char **p = a;
    printf("%p %p\n",*p,*(++p));
    return 0;  
}

结果为:004012B5  004012B5,在运算p之前已经进行了++p操作


求两数的平均数:

int f(int x,int y)
{
    return (x&y)+((x^y)>>1);
}

判断一个数是不是2的N次方:

!(x&(x-1));  //若是则为真,否则为假

 找出两个数中比较大的:

//方案一
int max = ((a+b)+abs(a-b))/2;

//方案二
int c = a-b;
c = unsigned(c) >> (sizeof(int)*8 -1);

将两个数交换:

//当a,b比较大的时候,会出现超界的问题
a = a+b;
b = a-b;
a = a-b;
//这个不会出现超界的问题
a = a^b;
b = a^b;
a = a^b;

内存对齐:

sizeof与strlen的:

形如 (void*)0的指针问题:

#define FIND(struc,e) (size_t)&(((struc*)0)->e)
//这段代码的意思是找出e在结构体struc中的偏移位置
//其中(struc*)0是将0强制转化为指向struc的指针

 typedef两个作用

  1. 使程序参数化,提高程序的可移植性。如果typedef声明的数据类型同机器有关,那么当移植到其他机器上时,只需改变typedef类型定义即可。
  2. 为程序提供更好的说明性,使新的类型名字面意义更直观。

 引用的用法:

  引用其实是一个变量的一个别名,并不产生副本。在底层实现上,引用其实保存的也是变量的实际地址,只不过系统将这些细节透明化了,让我们宏观上觉得引用是变量的一个别名。

  • 传递可变参数。如swap(int &a,int &b);
  • 传递大型对象。防止复制对象副本,提高效率
  • 引用返回值。比如一个函数返回了一个引用类型的值
    int& max(int& a,int& b)
    {
        return a>b?a:b;
    }    
    int main(int argc, char *argv[])
    {
        int b = 10;
        int c = 11;
        max(b,c) = max(b,c)+5;
    //c的值为16 }

    引用作为返回值必须遵守以下规则:①不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了'无所指'的引用,程序会入未知状态。②不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。③可以返回类成员的引用,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

  • 常引用。const int &ra = a;常引用的意思是,不能通过该引用ra来修改a的值。
    //有下面函数声明
    string foo();
    void bar(string &s);
    //下面的调用是非法的
    bar(foo());
    bar("Hello!");
    //将bar函数改成如下就可以通过
    void bar(const string &s);

    这里是因为foo()和"Hello"会产生一个临时对象,这些临时对象都是const类型的,将一个const的类型转化为非const类型,是不允许的。

  • 引用总结:①在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如的问题。②用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。③引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。④使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

拷贝构造函数:

  • 特殊的构造函数,函数名与类名相同,没有返回值
  • 只有一个参数,为同类对象的引用
  • 每个类都有一个拷贝构造函数,以实现同类对象之间的数据成员传递。如果程序员没有定义,则系统提供一个默认的。
  • 默认构造函数是将对象1各个域的值都拷贝给了对象2相应的域。当用赋值操作符“=”时,会调用拷贝构造函数。
View Code
class point
{
    public:
        point(int a,int b)
        {
            x = a;
            y = b;
        }    
        point(const point &p)
        {
            x = p.x;
            y = p.y;
        }    
        void print()
        {
            cout<<x<<" "<<y<<endl;
        }    
    private:
        int x,y;
};    

int main(int argc, char *argv[])
{
    point p1(30,40);
    point p2(p1);
    p1.print();
    p2.print();
  system("PAUSE");    
  return 0;
}
原文地址:https://www.cnblogs.com/7ants/p/3015065.html