NSMutableArray的扩容机制

一、简单介绍

其实NSMutableArray的扩容的话应该就是在于如果其容量不够了,就会去重新malloc一块新的区域,然后会复制旧的数据到新的区域,之后把旧的空间给free掉。

下面我们就先去查看下NSMutableArray的对象的内存信息


以及下面的那个就是指向第一个数据的指针的地址信息,

所以下面我们再去读取从它开始的100个字节的内存信息

上面的0x01000020b0其实就是Milk字符串的地址信息,通过lldb的po命令,根据地址把对象给打印出来

二、扩容机制

上面提到了指向数据的指针的指针,其实这个指针所指向的内容在数组容量不够的时候是会发生变化的,我们可以去创建分类然后写入下面这个方法,就可以实时的观察这个指针所指向内容的变化

-(void *)dataAddress
{
    void * address = (__bridge void *)self;
    //void ** 指向指针的指针,指针类型占据8个字节,+2就是往下挪16个字节 这里用*((long *)address +2)也是可以的
    return *((void **)address +2);
}

这个时候我们把数组的容量变为2,再去观察,观察后我们发现其实发生了频繁的改变的,只是扩容的规律还没有找到,不过也正好可以验证上面的NSMutableArray扩容的机制的说法。


三、实现数组扩容机制

在这篇文章中讲了下数组的实现,这里实现可变数组主要就是针对其内部的一个listInsert方法进行操作

/**插入数据*/
void listInsert(LinearList *list,int index,LinearListNodeValue value)
{
    if(list==NULL||index < 0||index > list->length)
    {
        return;
    }
    
    //可变数组进行扩容操作
    if(list->length == list->capacity)
    {
        //创建新的容量
        int newCapacity = list->capacity*2;
        
        //进行分配新的空间
        LinearListNodeValue *newValues = malloc(sizeof(LinearListNodeValue *)*newCapacity);
        
        //如果没有连续的存储空间,malloc也有可能失败。所以这里我们需要判断下
        if(newValues == NULL)
            return;
        
        //进行旧数据的拷贝到新的空间
        /*
         参数1:目标地址
         参数2:源地址
         参数3:字节数
         memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
         */
        memcpy(newValues, list->values, sizeof(LinearListNodeValue)*list->capacity);
        
        //释放旧的空间
        free(list->values);
        list->values = newValues;
        
        //修改容量属性
        list->capacity = newCapacity;
    }
    //从index开始到后面所有的数据都要进行挪动
    for(int i=list->length-1;i>=index;i--)
    {
        list->values[i+1] = list->values[i];
    }
    //设置新的值到index的位置
    list->values[index] = value;
    
    //数组的数量增加
    list->length++;
}

测试函数

void test3()
{
   //创建一个结构体,返回一个结构体
    LinearList * list = listCreat(2);
    
    //添加数据
    for(int i=0;i<20;i++)
    {
        listAdd(list, (LinearListNodeValue)i);
        //list代表的是结构体的地址,void ** 代表的也是8个字节,所以+1就可以了跳过了前面的长度和容量的内存,最前面的*表示取出这个指针指向的地址
        NSLog(@"数组长度:%d 数据地址:%p",listLength(list),*((void **)list+1));
    }
    listPrint(list);
}

输出结果


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值