Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22662
  • 博文数量: 8
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 141
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-20 00:03
文章分类
文章存档

2011年(1)

2008年(7)

我的朋友
最近访客

分类: 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 内存泄漏(养成newdelete配套使用的习惯)

即对(使用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& a )

{

assert( a_size>0 )

vector result(2);

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等库函数来操作

 

 

//Department源代码

#include <string>
#include <iostream>

using namespace std;

#include "ccc_empl.h"

/**
A department in an organization.
*/

class Department
{
public:
Department(string n);
void set_receptionist(Employee* e);
void set_secretary(Employee* e);
void print() const;
private:
string name;
Employee* receptionist;
Employee* secretary;
};

/**
Constructs a department with a given name.
@param n the department name
*/

Department::Department(string n)
{
name = n;
receptionist = NULL;
secretary = NULL;
}

/**
Sets the receptionist for this department.
@param e the receptionist
*/

void Department::set_receptionist(Employee* e)
{
receptionist = e;
}

/**
Sets the secretary for this department.
@param e the secretary
*/

void Department::set_secretary(Employee* e)
{
secretary = e;
}

/**
Prints a description of this department.
*/

void Department::print() const
{
cout << "Name: " << name << "\n"
    << "Receptionist: ";
if (receptionist == NULL)
    cout << "None";
else
    cout << receptionist->get_name() << " "
        << receptionist->get_salary();
cout << "\nSecretary: ";
if (secretary == NULL)
    cout << "None";
else if (secretary == receptionist)
    cout << "Same";
else
    cout << secretary->get_name() << " "
        << secretary->get_salary();
            
cout << "\n";
}

int main()
{
Department shipping("Shipping");
Department qc("Quality Control");
Employee* harry = new Employee("Hacker, Harry", 45000);
shipping.set_secretary(harry);
Employee* tina = new Employee("Tester, Tina", 50000);
qc.set_receptionist(tina);
qc.set_secretary(tina);
tina->set_salary(55000);
shipping.print();
qc.print();

return 0;
}

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