美文网首页ios学习之路iOS程序猿iOS Developer
C语言基础 - 实现动态数组并增加内存管理

C语言基础 - 实现动态数组并增加内存管理

作者: gwk_iOS | 来源:发表于2016-12-15 00:46 被阅读548次

    写在前面
    弄了下个人站...防止内容再次被锁定...所有东西都在这里面
    welcome~
    个人博客

    用C语言实现一个动态数组,并对外暴露出对数组的增、删、改、查函数
    (可以存储任意类型的元素并实现内存管理)

    这里我的编译器就是xcode

    分析:
    模拟存放 一个 People类 有2个属性 字符串类型:姓名 整型:年龄
    array 结构体 应当有 数组长度:length 空间:capacity 存储对象:value(任意类型)
    构造一个任意对象类.拥有retainCount属性.为内存计数器
    使用一次retainCount+1,当retainCount为0时 释放该对象指向的内存
    贴出部分代码

    //  Object.h
    #ifndef Object_h
    #define Object_h
    #include <stdio>
    //定义结构体
    typedef struct Object{
        int retainCount;
    }Object;
    //宏定义方法 方便书写
    #define OBJECTRETAIN(obj) objectRetain((Object*)obj)
    #define OBJECTRELEASE(obj) objectRelease((Object*)obj)
    #define GETRETAINCOUNT(obj) getRetainCount((Object*)obj)
    void objectRetain(Object *obj);
    void objectRelease(Object *obj);
    int getRetainCount(Object *obj);
    #endif /* Object_h */
    
    //  Object.c
    #include "Object.h"
    #include <stdlib>
    void objectRetain(Object *obj) {
     
        obj->retainCount ++;
    //    printf("retain计数+1 = %d\n",obj->retainCount);
    
    }
    
    void objectRelease(Object *obj) {
        obj->retainCount --;
        if (obj->retainCount <= 0) {
            free(obj);
        }
    //    printf("retain计数-1 = %d\n",obj->retainCount);
    
    }
    //获得当前计数
    int getRetainCount(Object *obj) {
        return obj->retainCount;
    }
    

    下面开始封装.
    首先是对原始数据的封装.

      1. 将char* 字符串类型 封装成String
    //  String.h
    #ifndef String_h
    #define String_h
    #include <stdio>
    typedef struct String{
        int retainCount;
        char *value;
    }String;
    String* newString(char* value);
    char* getStringValue(String* ins);
    #endif /* String_h */
    
    //  String.c
    #include "String.h"
    #include <stdlib>
    #include "Object.h"
    
    String* newString(char* value){
        String *str = malloc(sizeof(String));
        OBJECTRETAIN(str);
        str->value = value;
        return str;
        
    }
    char* getStringValue(String* ins){
        return ins->value;
    }
    
    • 2.将年龄的类型int封装成Interger
    //  Integer.h
    
    #ifndef Integer_h
    #define Integer_h
    
    #include <stdio>
    
    typedef struct Integer{
        int retainCount;
        int value;
    
    }Integer;
    
    Integer* newInteger(int value);
    int getIntegerValue(Integer* ins);
    #endif /* Integer_h */
    
    
    //  Integer.c
    
    #include "Integer.h"
    #include <stdlib>
    #include "Object.h"
    
    Integer *newInteger(int value) {
        Integer *new = malloc(sizeof(Integer));
        OBJECTRETAIN(new);
        new->value = value;
        return new;
    }
    
    int getIntegerValue(Integer* ins) {
        return ins->value;
    }
    
    • 3.定义数组中存放的类 包含 name 和 age 属性
    //  People.h
    
    #ifndef People_h
    #define People_h
    
    #include <stdio>
    #include "Integer.h"
    #include "String.h"
    
    typedef struct People{
        int retainCount;
        String* name;
        Integer* age;
        
    }People;
    
    People* newPeople(String *name,Integer *age);
    String* getName(People* people);
    Integer* getAge(People* people);
    #endif /* People_h */
    
    //  People.c
    
    #include "People.h"
    #include <stdlib>
    #include "Object.h"
    
    People* newPeople(String *name,Integer *age){
        People *newP = malloc(sizeof(People));
        OBJECTRETAIN(newP);
        newP->age = age;
        newP->name = name;
        return newP;
    }
    String* getName(People* people){
        return people->name;
    }
    Integer* getAge(People* people){
        return people->age;
    }
    
    • 4.准备工作都做完 ,下面我们来实现数组Array
    //  Array.h
    
    #ifndef Array_h
    #define Array_h
    
    #include <stdio>
    #include "People.h"
    #include "Object.h"
    typedef Object* AnyObject;
    
    typedef struct Array{
        int length;
        int capacity;
        AnyObject *value;
        
    }Array;
    
    Array* newArray();
    
    //增加数组元素
    void addElement(Array *array,AnyObject value);
    
    //删除
    Array* removeIndexAt(Array *arry,int index);
    
    //插入
    Array* insertIndexAt(Array *array,AnyObject value,int index);
    
    //查找
    AnyObject getValueIndexAt(Array *array,int index);
    
    //获取数组长度
    int getArrayLength(Array *array);
    
    //销毁
    void destroyArray(Array *array);
    
    //打印
    void printArray(Array *arr);
    
    
    #endif /* Array_h */
    
    //  Array.c
    
    #include "Array.h"
    #include <string>
    #include <stdlib>
    #include <assert>
    
    //分配空间
    static AnyObject* allocMemoryByCapacity(Array *arr){
        return malloc(sizeof(AnyObject) * arr->capacity);
    }
    
    //创建数组
    Array* newArray(){
        Array *arr = malloc(sizeof(Array));
        arr->length = 0;
        arr->capacity = 32;
        arr->value = allocMemoryByCapacity(arr);
        return arr;
    }
    
    //获取数组长度
    int getArrayLength(Array *array){
        return array->length;
    }
    
    //增加元素
    void addElement(Array *array,AnyObject value){
        if (array->length >= array->capacity) {
            array->capacity *= 2;
            AnyObject *oldValue = array->value;
            memcpy(array->value, oldValue, array->length*sizeof(AnyObject));
            free(oldValue);
        }
        OBJECTRETAIN(value);
        array->value[array->length] = value;
        array->length++;
    }
    
    //删除元素
    Array* removeIndexAt(Array *arry,int index){
        assert(index >= 0 && index < arry>length);  //断言 防止越界
        
        OBJECTRELEASE(getValueIndexAt(arry, index));
        
        arry->length -- ;
        for (int i = index-1; i < arry>length; i++) {
            arry->value[i] = arry->value[i+1];
        }
        return arry;
    }
    
    //在指定位置增加元素
    Array* insertIndexAt(Array *array,AnyObject value,int index){
        if (array->length >= array->capacity) {
            array->capacity *= 2;
            AnyObject *oldValue = array->value;
            memcpy(array->value, oldValue, array->length*sizeof(AnyObject));
            free(oldValue);
        }
        array->length++;
        
        //插入指定位置
        array->value[index-1] = value;
        //将元素后移
        for (int i = index; i < array>length; i++) {
            array->value[array->length] = array->value[array->length-i];
        }
        OBJECTRETAIN(value);
        return array;
    }
    
    
    
    //获取某个元素
    AnyObject getValueIndexAt(Array *array,int index){
        assert(index >= 0 && index < array>length);
        return array->value[index];
    }
    
    //销毁
    void destroyArray(Array *array){
        free(array->value);
        free(array);
        printf("数组被销毁\n");
    }
    //打印结果
    void printArray(Array *arr){
        for (int i = 0; i < arr>length; i++) {
            printf("位置:%d,姓名:%s,年龄:%d\n",i, getStringValue(getName((People*)getValueIndexAt(arr, i))),getIntegerValue(getAge((People*)getValueIndexAt(arr, i))));
        }
    }
    
    • 接下来就可以来测试数据了.
    //  main.m
    
    #import <Foundation>
    #import "People.h"
    #import "Array.h"
    #import "Object.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            Array *arr = newArray();
    
            People *p0 = newPeople(newString("张三"), newInteger(20));
            People *p1 = newPeople(newString("李四"), newInteger(16));
            People *p2 = newPeople(newString("王五"), newInteger(17));
            People *p3 = newPeople(newString("赵二"), newInteger(14));
            People *p4 = newPeople(newString("林三"), newInteger(22));
            People *p5 = newPeople(newString("小明"), newInteger(18));
            People *p6 = newPeople(newString("小红"), newInteger(25));
            People *p7 = newPeople(newString("小方"), newInteger(11));
            People *p8 = newPeople(newString("小花"), newInteger(19));
            People *p9 = newPeople(newString("小兔"), newInteger(22));
            People *p10 = newPeople(newString("新人"), newInteger(23));
            
            
            
            //增加元素
            addElement(arr, (Object *)p0);
            addElement(arr, (Object *)p1);
            addElement(arr, (Object *)p2);
            addElement(arr, (Object *)p3);
            addElement(arr, (Object *)p4);
            addElement(arr, (Object *)p5);
            addElement(arr, (Object *)p6);
            addElement(arr, (Object *)p7);
            addElement(arr, (Object *)p8);
            addElement(arr, (Object *)p9);
            
            
            //释放内存
            OBJECTRELEASE((Object*) p0);
            OBJECTRELEASE((Object*) p1);
            OBJECTRELEASE((Object*) p2);
            OBJECTRELEASE((Object*) p3);
            OBJECTRELEASE((Object*) p4);
            OBJECTRELEASE((Object*) p5);
            OBJECTRELEASE((Object*) p6);
            OBJECTRELEASE((Object*) p7);
            OBJECTRELEASE((Object*) p8);
            OBJECTRELEASE((Object*) p9);
            
    
            printf("增加10个元素\n");
            printArray(arr);
            
            printf("删除第3个元素\n");
            //删除第数组中某一个元素
            removeIndexAt(arr, 3);
            printArray(arr);
            
            printf("插入P10成为第4个元素\n");
            //插入
            insertIndexAt(arr, (Object *)p10, 4);
            printArray(arr);
            
            OBJECTRELEASE((Object*) p10);
    
            printf("查找第5个元素\n");
            //index从0开始 查找第5个元素 index=4
            printf("位置:%d,姓名:%s,年龄:%d\n",4, getStringValue(getName((People*)getValueIndexAt(arr, 4))),getIntegerValue(getAge((People*)getValueIndexAt(arr, 4))));
         
            //销毁数组
            destroyArray(arr);
            
        }
        return 0;
    }
    
    • 看下结果吧。
    array.png

    有兴趣的可以研究下哈

    相关文章

      网友评论

      • shyboy2012:不会内存泄露么 数组内的指针指向的People对象 没有手动去释放
        gwk_iOS:@shyboy2012 恩 多谢 你说的这个和楼上几位都是一样的 已经更改过了 。
      • CDAKhx:为啥 allocMemoryByCapacity() 里 hard code 了 People?
        CDAKhx:@gwk_ios :+1:🏻
        gwk_iOS:@桂一枫 谢谢提醒,这里的数组对象是people所以当时写的时候就直接这样写了,应该是 return malloc(sizeof(AnyObject) * arr->capacity);
      • 老司机Wicky:博主,想请教一下,当容量不够的时候capacity*2是什么考虑?而不是capacity+1。我理解的是不想频繁进行copy操作是么:flushed:但是capacity量级较大的时候*2会不会造成内存得浪费
        gwk_iOS:@老司机Wicky 是你说的这个情况,使用capacity是暂时分配的内存空间 ,确实没有考虑到量级大的层面。当然+1的话就太频繁了。感谢提醒。

      本文标题:C语言基础 - 实现动态数组并增加内存管理

      本文链接:https://www.haomeiwen.com/subject/upuwmttx.html