分类: C/C++
2007-08-08 16:57:23
C/C++读书笔记
1. 文件结构
C/C++文件结构包括头文件和实现文件,分别表示声明(declaration)和定义(definition)
头文件包括:版本说明、预处理、函数和(类)结构declaration
ifndef/define/endif 预处理块的作用:防止头文件的重复引用
#include <>:引用标准库中的头文件(编译器从标准目录开始搜索)
#include “”:引用非标准库中的头文件(编译器从用户工作目录开始搜索)
头文件只存放declaration,而不存放definition
尽量减少在头文件声明全局变量,少出现extern int value的声明
头文件作用:1)通过头文件调用库功能
2)加强类型安全检查
2. 表达式和简单运算符
运算符优先级:使用括号,避免使用默认优先级
从右至左的运算符结合规律:!,~,++, --, 强制类型转换, sizeof, +, -, *, &,?:
If语句: 1)布尔值与0的比较:if(flag)或if(!flag)
2)整型与0的比较:if(value==0)或if(value != 0)
3)浮点与0的比较:#define EPSINON 0.001
if (( x >= -EPSINON ) && ( x <= EPSINON ))
4)指针与0的比较:if(p == NULL)或if(p != NULL)
注:#define NULL ((void *)
问号表达式:condition ? x :y
循环语句的效率:在多重循环中,将长循环放内部,短循环放外部,减少CPU跨越循环层的次数
如果循环体内有判断语句,尽量将判断移植到循环外部,两者优缺点比较:效率和程序简洁。
|
程序简洁但效率低 效率高但程序不简洁
效率低的原因:多做了N-1次判断,而且在循环中打断了程序的“流水线”作业
switch语句:在每个case(除非想多分支同处理)包括default后面加上break
3. 常量
作用:书写容易,易于理解,易于修改,类型安全检测,
#define常量和const常量比较:const有类型安全检测;有些集成开发环境可以对const可以进行优化而#define不能;const是运行期间创建,#define常量是预编译 期间创建;const常量可以局限作用范围,如封装在类中,#define常量是全局的
4. 函数
输入参数:1)若是指针传递,不改变指向的值,应该加const
2)若不是内部数据类型以值的传递方式传递,应尽量用&引用传递,减少临时对象的创建、(拷贝)构造函数的调用、析构函数的调用,同时满足第一条,不改变其传入值的话,则加const修饰
返回值:灵活运用返回值和返回引用
函数入口和出口检测:在入口加上assert断言,在出口把关返回类型和对象或引用。
1) 函数不能返回指向“栈内存”的指针或引用
2) 确定返回的是值,指针还是引用
3) 避免在返回时创建临时对象并构造,拷贝,析构
5. 引用
引用必须与合法的存储单元相联系,一旦确定,引用不能改变关联关系
int i = 6; int j = 5; int &k = i; k = j; //则i和j的值都是6,但k还是i引用。
6. 内存管理
内存分配的方式:1)静态存储区,内存在编译期间已经分配好,程序在整个运行期间有效,例如:全局变量,static变量。
2)栈上内存,函数内部局部变量的分配方式,进入函数自动创建,出函数自动释放
3)堆上内存,由malloc,new等动态内存分配函数(操作符)分配的内存,必须调用free,delete手动释放
利用malloc/new分配内存后,立即用if(p == NULL)来防止错误
分配后初始化,注意数组的越界。
必须用free/delete释放内存,切与malloc/delete成对使用
释放后用p = NULL,防止出项“野指针”
数组和指针的区别:数组要么在静态存储区创建,要么在栈上创建,数组对应一组内存,在其生命周期内不变。数值名只是指向数组内存开始地址,他的值并不能改变,能改变的只是数组中存放的数据。指针可以指向任意类型,任意内存块。
内存容量:用sizeof()可以计算数组中元素的多少,而指针只能计算指针本身的大小。当数组作为输入参数传入函数时,自动转换成指针传递。不能传递大小
char a[] =“Hello”;
void func(char a[100]);
char *p = a;
sizeof(a); // = 6 sizeof(a); sizeof(p); // 与sizeof(char *)同效果,=4
利用函数参数来申请内存时,采用指向指针的指针才能申请到内存
void GetMemory(BYTE **p, size_t size)
{
*p = (BYTE *)malloc(sizeof(BYTE) * size);
}
编译器创建p的临时副本_p, 使得_p指向p所指向,即_p = p, 函数内部,实际上是改变_p的值,也就是改变了p的值,而p是指向指针的指针,p的值实际上是一个指针,他又指向新分配的内存区域。函数返回后,实际上也改变了p的值,即*p是指向新分配内存区域的指针。从而获得新申请的内存
指针本身释放不等于他指向的内存得到了释放,指向的内存得到释放也并不能使得指针自身释放,不要想当然的两者都释放了。安全的做法是在free/delete后,使得指针指向NULL,避免出现“野指针”
造成“野指针”的原因: 1)指针没有初始化
2)free/delete后,没有重置为NULL
3)指针操作超过其作用范围
内存耗尽的处理方式: 1)调用return终止本函数
2)调用exit终止本程序
3)为new/malloc设置异常处理函数
7. 类的构造函数、析构函数、赋值函数
每个类只有一个析构函数和赋值函数,但可以有多个构造函数。
一个空类,系统编译器自动生成如下函数:
|