您的位置:首页 > 编程语言 > C语言/C++

C/C++高质量编程笔记

2013-04-30 09:10 211 查看
转:http://hi.baidu.com/tofro/item/92b22e2e33a4510c73863e22

1 运算符优先级

( ),[],->,.,!,~,++,--,sizeof,(正负)+,-,(指针)*,&,*,/,%,+,-,《,》,...

2 if 语句判断条件
布尔型
if (flag) or if(!flag)
整型
if (value==0) or if (value!=0)
浮点型
if ((x>=-EPSINON) && (x<=EPSINON))
指针
if (P == NULL) or if (P != NULL)

3 循环语句效率
多重循环时,最短的循环放在最外层,以减小CPU跨切循环层的次数。

公共语句放在循环体外。

4 常量
#define MAX 100
const int MAX = 100;
const 常量有数据类型,编译器可以进行类型安全检查。
宏常量则没有,并且在字符替换时可能会产生意料不到的错误。

对外公开的常量放在头文件中,私密的常量放在定义文件的头部。

类中的常量
const数据成员只在某个对象生存期内是常量,不同对象的值可以不同。
class A
{
const int SIZE = 100;//错误
int array[SIZE];
}
const 数据成员的初始化只能在类构造函数的初始化表中进行:
class A
{
const int SIZE;
A(int size);
int array[SIZE];
}
A::A(int size) : SIZE(size)
{
}

5 函数设计
C语言中,函数的参数和返回值的传递方式有两种:值传递和指针传递,C++中多了引用传递。
(1)参数要书写完整,没有参数则用void填充
(2)如果参数是指针,且仅作输入用,则应在类型前加const
(3)如果输入参数是以值传递的方式传递对象,则宜改用const &的方法传递,省去临时对象的构造和析构。
(4)如果函数的返回值是一个对象,有些场合用“引用传递”可以提高效率,而有些场合只能用值传递,而不能用“引用传递”。

class String
{
//赋值操作
String& operate=(const String &other);
//相加操作
friend String operator+(const String &s1, const String &s2);
...
}
赋值函数中返回*this的引用。
相加操作函数中返回一个临时的String值,如果改用引用传递,那么函数返回值是一个指向局部对象的引用,由于函数结束时局部对象将自动销毁,将导致返回的引用无效。

6 函数内部实现的规则
(1)在函数的入口处,对参数的有效性进行检查。
使用assert,来防止非法参数(调用者出了差错)。

(2)在函数的出口处,对return 语句的正确性和效率进行检查。
* return 语句不可返回指向"栈内存"的指针或者引用。
* 搞清楚返回的究竟是值、指针还是引用。
* 如果返回值是一个对象,要考虑return语句的效率。
return String(s1+s2);

String temp(s1+s2);
return tem;
后者需要创建temp对象,同时完成初始化,然后拷贝构造函数把temp拷贝到保存返回值的外部存储单元中
,最后要销毁temp.前者只需创建一个临时对象并返回它,效率更高。

7 引用与指针的比较
* 引用被创建时必须初始化
* 一旦引用被创建,就不能改变引用的关系(指针可以改变所指的对象)
* 引用更安全

8 内存管理
内存分配的三种方式:
* 从静态存储区域分配。内存在程序编译的时候就已经分配好,在程序整个运行期间都存在。例如全局变量,static变量。
* 在栈上创建。函数内局部变量的存储单元在栈上创建,函数执行结束时自动释放。效率较高,但是分配的内存容量有限。
* 在堆上分配,动态内存分配,使用malloc或new创建,使用free或delete释放。

9 指针使用要点:
判断内存分配是否成功,初始化,不要越界,释放分配的内存,释放后赋NULL。

10 指针与数组的对比
数组在静态存储区或栈上创建,在生存期内对应一块内存,其地址与容量保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存。
* 修改内容
char a[]="hello";
a[0]='x';//正确
char *p="world";
p[0]='x';//错误

指针p指向常量字符串"world"(位于静态存储区,内容为world\0),常量字符串的内容是不可以被修改的。
* 内容复制与修改
复制字符串应用strcpy
比较字符串应用strcmp
* 计算内存容量
用运算符sizeof可以计算数组的容量,但是不能计算指针所指的内存容量。
char a[]="hello world";
char *p = a;
cout<<sizeof(a)<<endl;// 12
cout<<sizeof(p)<<endl;// 4

void Func(char a[100])
{
cout<<sizeof(a)<<endl;// 4
}

11 用函数分配内存
// 由于形参的原因,并不能为p分配内存,而且会造成内存泄漏
void GetMemory(char *p, int num)
{
p = (char *) malloc(sizeof(char)*num);
}

正确的方法:用指针的指针,用指针的引用,或者返回动态内存

void GetMemory1(char **p, int num)
{
*p = (char *) malloc(sizeof(char)*num);
}

void GetMemory1(char *&p, int num)
{
p = (char *) malloc(sizeof(char)*num);
}

char* GetMemory1(int num)
{
char *p = (char *) malloc(sizeof(char)*num);
return p;
}

12 malloc/free与new/free的区别
* malloc/free是C++/C语言的标准库函数,new/delete是C++的运算符
* new/free能自动执行对象的构造函数和析构函数

int *p1 = (int *)malloc(sizeof(int)*length);
int *p2 = new int[length];
Obj *a = new Obj;
Obj *b = new Obj(1);
Obj *c = new Obje[100](1);//错误

如果p不是NULL指针,那么free或delete对p连续操作再次会导致程序运行错误。

13 重载、内联、const、vitual:

extern跟C++的函数重载有关系。
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。

14 构造函数、析构函数与赋值函数

类的四个缺少函数:
A(void); //缺省的无参数构造函数
A(const A &a);// 缺省的拷贝构造函数
~A(void);//缺省的析构函数
A& operate=(const A &a);//缺省的赋值函数

缺省的拷贝构造函数与赋值函数,采用位拷贝而不是值拷贝。

例:String类的设计
class String
{
public:
String(const char *str=NULL);//普通构造函数
String(const String &other);//拷贝构造函数
~String();//
String& operator=(const String &other);//赋值函数
void Print();
private:
char *m_data;
};

String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[1];
*m_data = '\0';
}
else
{
int length = strlen(str);
m_data = new char[length+1];
strcpy(m_data, str);
}
}

String::~String()
{
delete []m_data;
}

String::String(const String &other)
{
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);
}

String& String::operator =(const String &other)
{
if(this==&other)
return *this;

delete []m_data;

int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);

return *this;
}

void String::Print()
{
cout<<m_data<<endl;
}

偷懒的方法
如果不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,以造成错误,怎么办?
只需将拷贝构造函数和赋值函数声明为私有,不用编写代码:
class A
{
...
private:
A(const A &a);// 私有的拷贝构造函数
A& operator=(const A &a);//私有的赋值函数
}

如果有人试图进行如下操作,编译器将指出错误:
A b(a);//调用了私有的拷贝构造函数
b = a; //调用了私有的赋值函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: