Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94309
  • 博文数量: 14
  • 博客积分: 490
  • 博客等级: 下士
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-20 11:00
文章分类

全部博文(14)

文章存档

2011年(1)

2008年(4)

2007年(9)

我的朋友
最近访客

分类: 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 *)0L)

问号表达式:condition x y

循环语句的效率:在多重循环中,将长循环放内部,短循环放外部,减少CPU跨越循环层的次数

如果循环体内有判断语句,尽量将判断移植到循环外部,两者优缺点比较:效率和程序简洁。

for ( ) {                                  if ( ) { 
    if ( ) {                                   for ( ) {

    }                                          }

    else {                                 else {

    }                                          for ( ) {
}                                              }

                                           }

    程序简洁但效率低                           效率高但程序不简洁

    效率低的原因:多做了N1次判断,而且在循环中打断了程序的“流水线”作业

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; //ij的值都是6,但k还是i引用。

6.   内存管理

内存分配的方式:1)静态存储区,内存在编译期间已经分配好,程序在整个运行期间有效,例如:全局变量,static变量。

              2)栈上内存,函数内部局部变量的分配方式,进入函数自动创建,出函数自动释放

              3)堆上内存,由mallocnew等动态内存分配函数(操作符)分配的内存,必须调用freedelete手动释放

 

利用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)指针没有初始化

                       2free/delete后,没有重置为NULL

                       3)指针操作超过其作用范围

 

内存耗尽的处理方式:      1)调用return终止本函数

                       2)调用exit终止本程序

                       3)为new/malloc设置异常处理函数

7.   类的构造函数、析构函数、赋值函数

每个类只有一个析构函数和赋值函数,但可以有多个构造函数。

一个空类,系统编译器自动生成如下函数: 

A(void); //缺省购置函数
~A(); //缺省析构函数
A(const A &a); //缺省拷贝构造函数
A &operator = (const A &a); //缺省赋值函数

阅读(1684) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~