建立一个struct,来管理一个动态增长的数组

本文深入探讨了使用C++实现动态增长数组的CStash结构,通过unsigned char作为基本数据类型,有效地管理不同类型的动态数据。同时,文章详细分析了字节序在数据转换过程中的作用,特别是在小端序X86体系结构下的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++编程思想,在介绍数据封装给了一个CStash的例子,大概的思想是,建立一个struct,来管理一个动态增长的数组。这个数组可以接受任何类型的基本数据类型。包括示例中的int和char,一个能保存多种数据类型的底层数据类型,当然是最小的类型也就是sizeof运算符返回为1的数据类型,综合考虑,原书中给出的unsigned char作为最基本的数据类型。实际上对应于标准的字节数组。对于这个转化过程,我写了一些代码验证了一些问题。顺便复习一下,计算机体系结构中的字节序的问题。

     以下是我的CStash实现代码:

#include<iostream>
#include<cstdlib>
using namespace std;
const int increment = 100;
struct CStash
{
    int size;//当前元素所占字节数
    int quantity;//当前容积(即包含未占用的和已占用的)
    int next;//当前元素个数(因为坐标从0开始,所以next实际上等于当前元素个数,又是下一个可以存放的空白位置)
    unsigned char *buffer;//字节数组
 
    //初始化
    void init(int sz)
    {
        size = sz;
        quantity = 0;
        next = 0;
        buffer = 0;
        cout << "Init......over!" <<endl;
    }
    //释放内存
    void cleanup()
    {
        if(buffer != 0)
            delete []buffer;
        cout << "Cleanup......over!" <<endl;
    }
 
    //添加元素
    int add(const void * element)
    {
        //当前元素数量超过容积,则动态增长
        if(next >= quantity)
            flate(increment);
        //转换为字节数组,因为指针的关系,首地址是不变的,数据内容并不会改变
        unsigned char *cur = (unsigned char *)element;
        //当前字节数(元素个数 * 每个元素的字节数)
        int startbytes = next * size;//从starybytes开始 都可以存放新的数据
        for(int i=0;i<size;i++)//因为一个元素是size个字节,复制size个字节到新空间
        {
            buffer[startbytes + i] = cur[i];
        }
        next++;//元素个数加1
        return next - 1;//返回当前最后一个元素,其实按照标准模版库的一般用法给next返回,也没啥问题
    }
 
    //获取当前位置的原书
    void* fetch(int index)
    {
        if(index >= next) return 0;
        //用引用返回,而不是局部指针
        return &(buffer[index * size]);
    }
 
    int count()
    {
        //当前元素个数
        return next;
    }
 
    void flate(int incre)
    {
        int newQuantity = quantity + incre;//新增长后元素数量
        int newSize = newQuantity * size;//新容器整个字节数
        int oldSize = quantity * size;//旧容器中字节数
        unsigned char *tmp = new unsigned char[newSize];//重新分配内存
        //复制旧元素
        for(int i=0;i<oldSize;i++)
        {
            tmp[i] = buffer[i];
        }
        delete []buffer;//释放旧元素内存
        buffer = tmp;//赋值新元素地址
        quantity = newQuantity;//修改容器容量
    }
};
int main()
{
    //验证unsigned char作为字节数组的可行性,刚好就是1字节
    cout << sizeof(unsigned char) <<endl;
    CStash s;
    //内存初始化
    s.init(sizeof(int));
    for(int i=0;i<100;i++)
    {
        s.add(&i);//添加元素
    }
    for(int i=0;i<s.count();i++)
    {
        cout << i << " : "<<*((int *)s.fetch(i))<<endl;//输出元素
    }
    cout << endl;
    //内存释放区域
    s.cleanup();
    //暂停
    system("pause");
}

现在分析上面代码值得学习的地方,首先为什么是无符号的字符数组,因为有符号的字节数组,因为符号的原因,会产生非预期的效果。其次添加元素和查找元素参数都是指针,指针变化的只是指针能访问数据类型的限制,而不是数据本身,所以这种转换并没有破坏数据本身。而且void * 使得程序能处理更通用的数据类型。还有这个动态增长的思想,其实标准库中有很多地方都有这种思想存在,这里的代码给人更直观的学习机会!

为了验证一个int(我的机器上32位环境下4字节)转换为unsigned char过程中发生了什么,这就涉及到了一点计算机体系结构的知识,也就是字节序的问题了。

验证程序如下:

#include<iostream>
#include<cstdlib>
#include<cstdio>
 
using namespace std;
void Convert(void *element,int size)
{
    //转换为字节数组指针
    unsigned char *tmp = (unsigned char *)element;
    for(int i=0;i<size;i++)
    {
        printf("%d ",(int)tmp[i]);//输出每个字节的内容
    }
    printf("\n");
}
 
int main()
{
    int a = 10;//可以设置10 1024等验证结论
    Convert(&a,sizeof(a));
    system("pause");
    return 0;
}

上面的程序将int * 转化为 unsigned char *之后查看四个字节的内容,得到了非常有意思的结果


10-----10 0 0 0
1024--0 4 0 0
看到没,0 4 0 0和10 0 0 0都说明是从低位开始放置数据的,低位数据是放在小地址上面的。按照维基百科(关键字:字节序)的说法,X86体系的计算机是小端序的,也就是从低字节开始增长。 为什么是0 4 0 0应为 2^10 = 1024 (二进制100 0000 0000) 十进制为0 0 4 0 反过来就是 0 4 0 0。小端序就是说地址是从低位开始增长,而且数据的低位放在低地址,高位放在高地址。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值