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两个作用
- 使程序参数化,提高程序的可移植性。如果typedef声明的数据类型同机器有关,那么当移植到其他机器上时,只需改变typedef类型定义即可。
- 为程序提供更好的说明性,使新的类型名字面意义更直观。
引用的用法:
引用其实是一个变量的一个别名,并不产生副本。在底层实现上,引用其实保存的也是变量的实际地址,只不过系统将这些细节透明化了,让我们宏观上觉得引用是变量的一个别名。
- 传递可变参数。如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相应的域。当用赋值操作符“=”时,会调用拷贝构造函数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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; }