第一章C++编程基础(指针带来的弹性)

1.6 指针带来的弹性

pointers allow for flexbility

 

 

前一节的解法有两大缺点。一是,上限是六个数列;如果用户猜完了六个数列,程序将会毫无预兆结束。二是,这个方法每次都以同样的顺序显示六组元素。

那么如何增加函数的弹性呢?

 

一种可能的解法是同时维护六个vector,每个数列使用一个。每个vector存储某一数量的元素值。每一次迭代中,我们从不同的vector取出一组元素值。当第二次用到相同的vector时候,便以不同的索引值取出vector中的元素。这个方法可以解决问题。

 

这一节我们将通过使用指针(Pointer),舍弃以名称指定的方式,间接地访问每个vector,借此达到透明化的目的。指针为程序引入了一层间接性。我们可以直接操作指针(代表特定的内存地址),而不再直接操作对象。在我们的程序中,我定义了一个可以对整数vector寻址的指针。每一次迭代循环中,便更改指针值,使他定位在不同的vector,随后指针操作行为不需要更改。

 

指针

在我们的程序中,指针主要做两件事。它可以增加程序本身的弹性,但同时也增加了直接操作对象时所没有的复杂度。

如何定义对象:
int ival=1024;
//将ival定义为一个int对象,并给与初值1024.
//ival是一个Int对象,初值为1024

 


*的用法:
int *p;
//当我们要定义某个特定类型的指针时,必须在类型名称后面加上*号。
//*p是一个int类型的指针

 

 

如何为指针进行赋值:
ival;//计算ival的值
&ival;//计算ival所在的内存地址

 

 

取址操作:
int *p=&ival;

 

 

取得指针所指的对象:
if(!*p=1024)//读取ival的值
*p=1024;//写值至ival
//要访问指针所指向的对象,我们必须对该指针进行提领(dereference)操作。即是在指针之前使用*号。

 

 

指针拥有双重的性质:既可以让我们操作指针所包含的内存地址,也可以让我们操作指针所指的对象的值。
例如:pi;//计算pi所持有的内存地址
     *pi;//求出ival的值即是pi所指向的对象

 

 

指针也可以不指向任何对象,其地址值为0.有时候我们称为null指针。任何指针都可以初始化,或是另其值为0、
例如: int *p=0;
       double *pd=0;
       string *pd=0;//初始化每个指针,使它们不指向//任何对象

 

 

但如果pi不指向任何对象,则提领Pi会导致未知的执行结果。这意味着,在使用指针时,必须在提领之前先确定它的确指向某对象。我们可以设置空指针null
为了防止对null指针进行提领操作,我们可以检验该指针所持有的地址是否为0.
例如: if(pi&&pi !=1024)
       *pi=1024;

 

 


表达式 if(pi&&....)
只有pi持有一个非零值时,其求值结果才是true。
如果其值是false,那么AND运算符就不会对其第二表达式求值。

 

 

 

表达式if(!pi)//当pi的值为0时,此表达式方为true.
我们通常逻辑运算符NOT,来检验指针是否为null。

 

 

 

程序设计:

以下是我们的六个vector对象(代表六个数列)
vector<int>fibonacci,lucas,pell.triangular,square,pentagonal;


当我们需要一个指针,指向一个元素类型为int的vector时,该指针应该是什么模样呢?
type_of_object_pointed_to*name_of_pointer_object

 

由于我们需要指针系指向vector<int>,因此我们把它命名为pv,并给定初值0;

 

法一:
vector<int>*pv=0;
//pv可以依次指向每一个表示数列的vector。

将数列的内存地址赋值给pv:

pv=&fibonacci;
//...
pv=&lucas;
这种方式会牺牲程序的透明性,另一种方案是将每个数列的内存地址存入某个vector中,这样我们就可以通过索引的方式,透明的访问这些数列。

 

法二:

const ine seq_cnt=6;


//一个指针数组,大小为seq_cnt
//每个指针都指向vector<int>对象

//cnt的英文为count,计数器


vector<int>*seq_addrs[seq_cnt]={
&fibonacci,&lucas,&pell,
&triangular,&square,&pentagonal
};
seq_addrs是个array,其元素类型为vector<int>*.
seq_addrs[0]所持有的值是fibonacci vector的地址,seq_addrs[1]的值是lucas vector的地址,以此内推。我们通过一个索引值而非其名称来访问各个vector:

vector<int>*current_vec=0;
//....
for(int ix=0;ix<seq_cnt;++ix)
{
current_vec=seq_addrs[ix];
//所有要显示的元素都通过current_vec间接访问
}

 

调用<cstflib>中的rand()和srand()函数

 

最后一个问题是,在上述程序中,程序的执行结果完全可以预测。要给用户猜测的数列,总是按照fibbonacci,lucca,pell...的次序出现。我们希望让数列出现的顺序随机(randomize)这可以通过c语言中的rand()和srand()两个函数达成:
#include<cstdlib>
srand(seq_cnt)
seq_index=rand()%seq_cnt;
current_vec=seq_addrs[seq_index];

rand()和srand()都是标准库提供的所谓伪随机数生成器(pseudo-random number)。srand()参数是所谓随机数生成器的种子。要知道,每次调用rand(),都会返回一个介于0和”int所能代表的最大整数“间的一个整数。现在我们必须将该值限制在0~5,以便成为本例的一个有效的索引。这两个函数的声明位于cstdlib头文件。

 

 

dot运算符和arrow运算符

 

使用class object的指针,和使用内置类型的指针略有不同。这是应为class object关联了一组我们可以调用(invoke)的操作(operation).举例说,欲检查fibonacci vector的第二个元素是否为1,我们可能会这么写:
if(!fibonacci.enmpty()&&(fibonacci[1]==1))
如何才能间接通过pv达到同样的效果呢?上例中的fibonacci和empty()之间的句点,称之为dot成员选择运算符(member selection operator),用来选择我们想要的操作。如果要通过指针来选择操作,必须改用arrow(而非dot)成员选择运算符:
!pv->empty()
由于指针并未指向任何对象,所以在调用empty()之前,应该先检验pv是否为0:
pv&& ! pv->empty()
最后,如果要使用下标运算符,(subscript operator),我们必须要先提领pv。由于下标运算符的优先级较高,因此pv提领操作的两旁必须加上小括号:
if(pv && ! pv->enpty()&&((*pv)[1]==1))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值