分类: C/C++
2008-06-30 00:49:08
目标
-- 知道怎么样声明、初始化以及使用指针
-- 熟悉怎样动态分配内存和释放内存
-- 学会在编程环境中使用指针
-- 知道怎样避免指针悬挂和内存泄漏的常见错误
-- 理解数组和指针之间的关系
-- 知道怎样在字符串对象和字符指针之间转换
10.1 指针和分配内存
new语法
new type_name
new type_name(expression1,expression1,....,expressionn)
--new为新的对象在堆(heap)中分配内存,并返回该对象的指针
指针变量定义
type_name * variable_name;
type_name * variable_name = expression;
-- 定义一个指针变量,同时还可以为它提供初值
指针的递引用
*pointer_expression
pointer_expression->class_member
-- 访问指针所指向的对象
错误10.1 指针与所指数据的混淆
* 指针的有限操作
-- 给指针变量赋值
-- 将指针变量与其他指针或NULL进行比较
-- 访问指针所指向的值
注意函数的形参 传递的是指针还是指针指向的数据
错误10.2 在一个语句中定义两个指针变量
仍是声明时 * 的位置问题,Employee* p, q;语句只声明了一个指针变量
10.2 释放动态内存
delete表达式
delete pointer_expression
-- 释放指针所指向的动态存储空间,并允许该内存空间再次分配
例子:
void g()
{
Employee* boss;
boss = new Emloyee(....); //上面两句最好还是写在一起,避免误用未初始化指针
.....
delete boss;
}
-- 定义一个指向Employee对象的指针变量boss,但它首先是指向一个随机地址
-- 在堆里面分配Employee对象,并使boss指针指向它
-- 调用delete函数删除分配给Emloyee对象的内存空间
-- 如果不调用delete的话,boss指针在函数结束时会销毁,但是它指向的内存(堆里)并没有销毁
错误10.3 悬挂指针(及时初始化局部变量)
dangling,指的是使用一个未被初始化或者已经被删除的指针。
-- 如果指针的地址空间不允许访问,程序会停止运行,但如果该随机的地址刚好在允许访问的地址空间内,就会破坏所指向地址上的数据,严重会造成程序崩溃
错误10.4 内存泄漏(养成new和delete配套使用的习惯)
即对(使用new运算符)动态分配的内存从不释放,从不被释放的内存块称为内存泄漏(memory leak)
-- 严重会耗尽程序所有的可用内存,这些动态内存只会在程序结束时被系统回收
高级10.2 取地址运算符
Employee harry;
Employee* p = &harry;
注意:绝对不能释放使用运算符&获得的地址空间,这样会造成后续的分配内存(new)出错!
10.3 指针的常见用法
例子:利用指针指向NULL与非空的特性,来类成员中的可选对象
class Department
{
...
private:
string name;//
Employee *receptionlist; //接待员,无则指向NULL,有则指向员工(因为可有可无),或者可以共享其他部门的一个秘书(呵呵,真是节省人力啊!)
}
Department::Department(String n){
name = n;
receptionist = NULL;
}
Department::set_receptionist(Employee *r){
receptionist = r;
}
思想:指针在构造多个不同的变量共享同一对象的这种“n : 1”关系模型
10.4 数组和指针
数组/指针的二重性法则(array/pointer duality law)
-- 数组可以通过下标或者指针来访问
形参传递
double maximum(const double a[], int a_size);
double maximum(const double* a, int a_size); //两句等价!
高级10.4 通过指针遍历数组
通过上面的两个语句得出,既然传递了数组的首地址,那就可以通过指针遍历数组了
质量忠告10.1 程序应清晰,而不应巧妙
严防下面这个例子的程序出现!
while(--a_size > 0 )
if( *++a_size >0 )
highest = *1;
错误10.5 数组和指针声明的混淆
int *p; //p是指针,注意声明后应该对其初始化
int a[10]; //a是数组
int a [] = {2, 3, 4, 5, 6, 7, 11}; //a是数组
void f( int a[] ); //a是指针
错误10.6 返回局部数组的指针
double *minmax( const double a[], int a_size )
{
assert( a_size>0 )
double result[2];
result[0] = a[0];
result[1] = a[1];
for( int i = 0; i ......计算result[0]和result[1]; } return result; } result数组是函数minmax的局部变量,函数退出后局部变量的内存空间就会被释放,或会被其他变量覆盖。 double a[] = {3, 5,10, 12}; double* mm = minimax(a,4); cout< 这个mm[0]和mm[1]很大可能会因为调用cout函数而产生新的子函数堆栈分配,造成上一行minimax函数调用退出后的堆栈被覆盖掉。 解决之道: 1、返回一个动态分配空间的指针; 2、避免同时使用数组和指针,用向量代替。 double *minmax( const vector { assert( a_size>0 ) vector result[0] = a[0]; result[1] = a[1]; for( int i = 0; i ......计算result[0]和result[1]; } return result;//这样就OK了 } 高级10.5 动态分配数组 Employee *staff = new Employee[staff_capacity]; ..... delete[] staff; 忠告:尽量使用vector对象代替动态数组 10.5 指向字符串的指针 string name = "Harry"; 当在表达式中使用字符串“Harry”时,编译程序将为其分配一个6个字符的数组,字符串表达式的值为指向字符串首字母的地址,类型为char*。 等价于: char *p = "Harry"; name = p; 可以通过string的成员函数c_str得到一个指向字符串对象首字符的指针 错误10.7 混淆字符指针和数组 数组的复制要使用strcpy, strcpy等库函数来操作
|