Symbian 中的动态数组 CArrayX

Symbian OS 中的动态数组CArrayX的存储方式分为连续存储(Flat)和分段存储(Segmented buffer)两种。

对于Flat方式,多用于查找比较频繁的地方。对于Segmented方式,多用于存储空间大小经常发生变化的时候。

由于存在连续存储和分段存储两种不同形式的存储,CArray可根据存储形式和存储内容的不同分为4种。

(1)Fix类型,每个元素都拥有相同的长度。
(2)Var类型,各元素拥有不同的长度,每给对象都保存在各自的堆单元中,数组空间中保存着各个元素的指针。
(3)Pak类型,数组中每个元素都有可变的长度,类似于描述符对象,每个元素前面都有其自身的长度信息。
(4)Ptr类型,指针数组。

在选择存储形式时,要考虑如下问题:

(1)是否需要经常的重新分配
(2)数据元素插入和删除的频率
(3)访问数据成员的速度

 

下表中列出了可以使用的CArray类型:

 

名称 元素大小 缓冲器类型 用法
CArrayFixFlat 固定大小 平面 很少进行分配时,用于存储固定大小的T类和R类对象
CArrayVarFlat 可变大小 平面 很少进行分配时,用于存储可变大小的T类和R类对象
CArrayPtrFlat 指针 平面 很少进行分配时,用于对象指针
CArrayPakFlat 大小可变(压缩) 平面 很少进行分配时,用于在一个堆单元中存储可变大小的T类或R类对象
CArrayFixSeg 固定大小 片断 频繁进行分配时,用于存储固定大小的T类和R类对象
CArrayVarSeg 可变大小 片断 频繁进行分配时,用于存储可变大小的T类和R类对象
CArrayPtrSeg 指针 片断 频繁进行分配时,用于存储对象指针

 从上表中,我们知道了CArray提供了多个版本的类用来提供给用户更多的选择。通常我们常用的有4种:

CArrayVarFlat:存储可变长度元素,存储方式为Flat。

CArrayVarSeg:存储可变长度元素,存储方式为Segment。

CArrayPakFlat:存储固定的或者可变长度的元素,而且每个元素都保留自己的长度信息。

CArrayPtrFlat:存储数组指针,存储方式为Segment。

 

◎ 下面,我们将使用CArrayFixFlat和CArrayFixSeg来写一个例子,实际上,在下面的那个例子里,两个数组是完全可以互换的,因此,我只需要写一个就足够了。

 

在给出例子之前,我们还要再讲一下CArray的排序与查找,由于CArrayX不同于RArray类,因此,在查找与排序方面也是有很大区别的。

 

对于排序,我们首先要构造一个适当的键,这个键将是你排序的根本,在声明键时要指明排序的类型、字段偏移量和文本长度。其次,将键传入Sort()方法中进行排序。

 

下表为CArray类不同类型时,所要用到的键类型:

 

名称 键类型 说明
CArrayFixFlat TKeyArrayFix  
CArrayVarFlat TKeyArrayVar  
CArrayPtrFlat TKeyArrayFix派生类 需要特殊实现
CArrayPkgFlat TKeyArrayVar  
CArrayFixSeg TKeyArrayFix  
CArrayVarSeg TKeyArrayVar  
CArrayPtrSeg TKeyArrayFix派生类 需要特殊实现

 

由于下面的例子中,我们使用了CArrayFixFlat,因此我们的键就是TKeyArrayFix(依照上表)

TKeyArrayFix(TInt anOffset, TKeyCmpText aType)

这两个参数是:

 

    TInt    anOffset —类中字段的偏移量

    TKeyCmpText    aType — 对应字段的类型

 

对于第一个参数,Symbian中提供了一个_FOFF(c,f)宏来取得类中字段的偏移量,其中,c为类命,f为字段命。如:_FOFF(TStudent,iSName);

 

对于第二个参数,我们通常是可以有据可循的,请见下表:

 

字段类型 键类型
数据 ECmpTInt8、ECmpTInt16、ECmpTInt32、ECmpTInt、ECmpTUint8、ECmpTUint16、ECmpTUint32、ECmpTUint、ECmpTInt64
文本 ECmpNormal、ECmpNormal8、ECmpNormal16、ECmpFolded、ECmpFolded8、ECmpFolded16、ECmpCollated、ECmpCollated8、ECmpCollated16、

 

class TStudent
{
public:
    TStudent(const TDesC& aSName,TUint aSNo,TReal aScore);
public:
    TUint iSNo;
    TReal iScore;
    TBuf<10> iSName;
};

TStudent::TStudent(const TDesC& aSName,TUint aSNo,TReal aScore)
{
    iSNo = aSNo;
    iScore = aScore;
    iSName = aSName;
}

void ManageStu()
{
    //使用CArrayFixFlat,很少进行分配时,用于存储固定大小的T类和R类对象
    
    CArrayFixFlat<TStudent>* StuArrayFlat;
    //这里也可以改成CArrayFixSeg<TStudent>* StuArraySeg;    

    StuArrayFlat = new(ELeave)CArrayFixFlat<TStudent>(5);

    CleanupStack::PushL(StuArrayFlat);

    //分配空间存储两个学生的信息
    _LIT(KSTUDENT1,"GuanYabei");
    _LIT(KSTUDENT2,"WuMingshi");
    _LIT(KRETURN,"\n");
    
    TBuf<10> StuName1 = KSTUDENT1;
    TBuf<10> StuName2 = KSTUDENT2;

    //初始化两个学生的信息(姓名,学号,分数)
    TStudent stu1(StuName1,1,100.0);
    TStudent stu2(StuName2,2,99.5);

    //添加到数组中,请注意,用到的是AppendL()方法,它是可能引起异常的
    StuArrayFlat->AppendL(stu1);
    StuArrayFlat->AppendL(stu2);

    // 显示所有的学生信息
    _LIT(KFORMAT2,"id is %d");
    _LIT(KFORMAT3,"score is %f");

    for(TInt i=0; i<StuArrayFlat->Count(); i++)
    {
        console->Printf(_L("name is "));
        console->Printf((*StuArrayFlat)[i].iSName);
        // 如果你觉得指针括号太多而不够美观,我们也可以使用另一种方法
        // 即,使用At()函数
        // 如:console->Printf(StuArrayFlat->At(i).iSName);
        console->Printf(KRETURN);
        console->Printf(KFORMAT2,(*StuArrayFlat)[i].iSNo);
        console->Printf(KRETURN);
        console->Printf(KFORMAT3,(*StuArrayFlat)[i].iScore);
        console->Printf(KRETURN);
    }
    console->Printf(_L("Press any key to continue\n"));
    console->Getch();

    //删除数组中的元素
    console->Printf(_L("Delete first Student\n"));
    StuArrayFlat->Delete(0);
    for(i=0; i<StuArrayFlat->Count(); i++)
    {
        console->Printf(_L("name is "));
        console->Printf((*StuArrayFlat)[i].iSName);
        console->Printf(KRETURN);
        console->Printf(KFORMAT2,(*StuArrayFlat)[i].iSNo);
        console->Printf(KRETURN);
        console->Printf(KFORMAT3,(*StuArrayFlat)[i].iScore);
        console->Printf(KRETURN);
    }
    console->Printf(_L("Press any key to continuce\n"));
    console->Getch();

    //修改第一个学生的姓名
    console->Printf(_L("Modify first student's name\n"));
    console->Printf(_L("first student old name is "));
    console->Printf((*StuArrayFlat)[0].iSName);
    console->Printf(KRETURN);

    (*StuArrayFlat)[0].iSName = _L("GuanYabei");

    console->Printf(_L("first student new name is "));
    console->Printf((*StuArrayFlat)[0].iSName);
    console->Printf(KRETURN);

    console->Printf(_L("Press any key to continue\n"));
    console->Getch();

    //以姓名方式查找
    console->Printf(_L("Find student by name\n"));

    //建立主键,对于不同类型的CArray有不同的主键类型
    //_FOFF(c,f)宏来取得类中字段的偏移量
    TKeyArrayFix nameKey(_FOFF(TStudent,iSName), ECmpNormal);

    TInt findPos;
    TStudent S(StuName1,0,0);
    console->Getch();
    if(StuArrayFlat->Find(S, nameKey, findPos) != KErrNotFound)
    {
        //查找对象是S,按ECmpNormal格式
        console->Printf(_L("findPos is %d "),findPos);
        console->Printf((*StuArrayFlat)[findPos].iSName);//直接引用findPos的值,有的书上写findPos-1,这是错误的!
    }
    console->Printf(KRETURN);

    console->Printf(_L("Press any key to continue\n"));
    console->Getch();

    //以成绩方式排序
    TKeyArrayFix scoreKey(_FOFF(TStudent,iScore), ECmpTInt32);
    User::LeaveIfError(StuArrayFlat->Sort(scoreKey));

    for(i=0;i<StuArrayFlat->Count();i++)
    {
        console->Printf(_L("name is "));
        console->Printf((*StuArrayFlat)[i].iSName);
        console->Printf(KRETURN);
        console->Printf(KFORMAT2,(*StuArrayFlat)[i].iSNo);
        console->Printf(KRETURN);
        console->Printf(KFORMAT3,(*StuArrayFlat)[i].iScore);
        console->Printf(KRETURN);
    }

    CleanupStack::PopAndDestroy();
} 
 

你可能感兴趣的:(C++,c,C#,F#,Symbian)