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

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

2012-01-01 00:20 190 查看
怕忘记的一些重点,呵呵。

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; //调用了私有的赋值函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: