C/C++实现动态数组的示例详解

 更新时间:2023年08月16日 10:28:50   作者:lyshark  
动态数组相比于静态数组具有更大的灵活性,因为其大小可以在运行时根据程序的需要动态地进行分配和调整,本文为大家介绍了C++实现动态数组的方法,需要的可以参考下

动态数组相比于静态数组具有更大的灵活性,因为其大小可以在运行时根据程序的需要动态地进行分配和调整,而不需要在编译时就确定数组的大小。这使得动态数组非常适合于需要动态添加或删除元素的情况,因为它们可以在不浪费空间的情况下根据需要动态增加或减少存储空间。

动态数组的内存空间是从堆(heap)上分配的,动态数组需要程序员手动管理内存,因为它们的内存空间是在程序运行时动态分配的。程序员需要在使用完动态数组后手动释放其内存空间,否则可能会导致内存泄漏的问题,进而导致程序崩溃或者运行缓慢。因此,在使用动态数组时,程序员需要特别注意内存管理的问题。

读者需自行创建头文件dynamic.h并拷贝如下动态数组代码实现;

#include <stdlib.h>
#include <string.h>
struct DynamicArray
{
    void **addr;   // 存放元素或结构体的首地址
    int curr_size; // 存放当前元素数量
    int max_size;  // 存放当前最大元素数
};
// 初始化动态数组,初始化后直接返回数组的首地址
struct DynamicArray *InitDynamicArray(int size)
{
    // 如果小于0则说明没有元素,返回NULL
    if (size <= 0)
    {
        return NULL;
    }
    // 分配结构指针,此处分配的是结构体指针,并没有分配空间
    struct DynamicArray *ptr = malloc(sizeof(struct DynamicArray));
    if (ptr != NULL)
    {
        // 将当前元素索引设置为0
        ptr->curr_size = 0;
        // 默认最大数组元素数为size
        ptr->max_size = size;
        // 实际分配存储空间大小是max_size最大元素
        ptr->addr = malloc(sizeof(void *) * ptr->max_size);
        return ptr;
    }
    return NULL;
}
// 将元素插入到指定位置
void InsertDynamicArray(struct DynamicArray *ptr, int index, void *data)
{
    // 判断如果数组不为空,或者是data不为空,则继续执行
    if (ptr != NULL || data != NULL)
    {
        // 如果插入位置小于当前0,或者大于当前元素总个数
        if (index < 0 || index > ptr->curr_size)
        {
            // 就自动把它插入到元素的末尾位置
            index = ptr->curr_size;
        }
        // 紧接着判断当前元素数是否大于最大值,大于则分配空间
        if (ptr->curr_size >= ptr->max_size)
        {
            // 分配一块更大的空间,这里分配原始空间的2倍
            int new_max_size = ptr->max_size * 2;
            void **new_space = malloc(sizeof(void *) * new_max_size);
            // 接着将原来空间中的数据拷贝到新分配的空间
            memcpy(new_space, ptr->addr, sizeof(void *) * ptr->max_size);
            // 释放原来的内存空间,并更新指针的指向为新空间的地址
            free(ptr->addr);
            ptr->addr = new_space;
            ptr->max_size = new_max_size;
        }
        // 开始移动元素,给ins元素腾出空来
        for (int x = ptr->curr_size - 1; x >= index; --x)
        {
            // 从后向前,将前一个元素移动到后一个元素上
            ptr->addr[x + 1] = ptr->addr[x];
        }
        // 设置好指针以后,开始赋值
        ptr->addr[index] = data;
        ptr->curr_size++;
        return 1;
    }
    return 0;
}
// 遍历数组中的元素,这里的回调函数是用于强制类型转换,自定义输出时使用
void ForeachDynamicArray(struct DynamicArray *ptr, void(*_callback)(void *))
{
    if (ptr != NULL || _callback != NULL)
    {
        for (int x = 0; x < ptr->curr_size; x++)
        {
            // 调用回调函数并将数组指针传递过去
            _callback(ptr->addr[x]);
        }
    }
}
// 根据位置删除指定元素,index = 元素的下标位置
void RemoveByPosDynamicArray(struct DynamicArray *ptr, int index)
{
    if (ptr == 0)
        return 0;
    // 判断当前插入位置index必须大于0且小于curr_size
    if (index > 0 || index < ptr->curr_size - 1)
    {
        for (int i = index; i < ptr->curr_size - 1; ++i)
        {
            // 每次循环都将后一个元素覆盖到前一个元素上
            ptr->addr[i] = ptr->addr[i + 1];
        }
        // 最后当前元素数量应该减去1
        ptr->curr_size--;
    }
}
// 按照元素的指定值进行元素删除,这里需要回调函数指定要删除元素的值是多少
void RemoveByValueDynamicArray(struct DynamicArray *ptr, void *data, int(*compare)(void*, void *))
{
    if (ptr != NULL && data != NULL && compare != NULL)
    {
        for (int i = 0; i < ptr->curr_size; ++i)
        {
            if (compare(ptr->addr[i], data))
            {
                RemoveByPos_DynamicArray(ptr, i);
                break;
            }
        }
    }
}
// 销毁数组
void DestroyDynamicArray(struct DynamicArray *ptr)
{
    if (ptr != NULL)
    {
        if (ptr->addr != NULL)
        {
            free(ptr->addr);
            ptr->addr = NULL;
        }
        free(ptr);
        ptr = NULL;
    }
}

上述代码的使用很容易,如下代码实现了动态数组的基本操作,包括创建动态数组、插入元素、删除元素、遍历元素和销毁动态数组。其中定义了一个自定义结构体Student,用于作为动态数组的元素。在使用InitDynamicArray函数创建动态数组之后,使用InsertDynamicArray函数将四个元素插入到动态数组中,其中第三个元素插入的位置为3。然后使用RemoveByPosDynamicArray函数根据下标移除第一个元素,使用RemoveByValueDynamicArray函数根据元素的值移除第二个元素,其中使用myCompare回调函数对比元素。最后使用ForeachDynamicArray函数遍历所有元素,并使用MyPrint回调函数输出元素的值。最终销毁动态数组,释放内存。

#include "dynamic.h"
// 自定义结构体
struct Student
{
    int uid;
    char name[64];
    int age;
};
// 回调函数用于输出元素
void MyPrint(void *data)
{
    // 强制类型转换,转成我们想要的类型
    struct Student *ptr = (struct Student *)data;
    printf("Uid: %d --> Name: %s \n", ptr->uid, ptr->name);
}
// 回调函数用于对比元素
int myCompare(void *x, void *y)
{
    struct Student *p1 = (struct Student *)x;
    struct Student *p2 = (struct Student *)y;
    if (strcmp(p1->name, p2->name) == 0)
    {
        return 1;
    }
    return 0;
}
int main(int argc, char *argv[])
{
    //创建动态数组
    struct DynamicArray *ptr = InitDynamicArray(5);
    // 创建元素
    struct Student stu1 = { 1001, "admin1", 22 };
    struct Student stu2 = { 1002, "admin2", 33 };
    struct Student stu3 = { 1003, "admin3", 44 };
    struct Student stu4 = { 1004, "admin4", 55 };
    // 将元素插入到数组
    InsertDynamicArray(ptr, 0, &stu1);
    InsertDynamicArray(ptr, 1, &stu2);
    InsertDynamicArray(ptr, 3, &stu3);
    InsertDynamicArray(ptr, 4, &stu4);
    // 根据下标移除元素
    RemoveByPosDynamicArray(ptr, 0);
    // 删除元素是p_delete的数据
    struct Student p_delete = { 1002, "admin2", 33 };
    RemoveByValueDynamicArray(ptr, &p_delete, myCompare);
    // 遍历元素
    ForeachDynamicArray(ptr, MyPrint);
    // 销毁顺序表
    DestroyDynamicArray(ptr);
    system("pause");
    return 0;
}

到此这篇关于C/C++实现动态数组的示例详解的文章就介绍到这了,更多相关C++动态数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现简单推箱子小游戏

    C语言实现简单推箱子小游戏

    这篇文章主要为大家详细介绍了C语言实现推箱子小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • c++读取和写入TXT文件的整理方法

    c++读取和写入TXT文件的整理方法

    今天小编就为大家分享一篇c++读取和写入TXT文件的整理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • C/C++ProtoBuf使用小结

    C/C++ProtoBuf使用小结

    ProtoBuf全称:protocol buffers,直译过来是:“协议缓冲区”,是一种与语言无关、与平台无关的可扩展机制,用于序列化结构化数据,这篇文章主要介绍了C/C++ProtoBuf使用,需要的朋友可以参考下
    2024-01-01
  • C++实现LeetCode(79.词语搜索)

    C++实现LeetCode(79.词语搜索)

    这篇文章主要介绍了C++实现LeetCode(79.词语搜索),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 老生常谈C++的单例模式与线程安全单例模式(懒汉/饿汉)

    老生常谈C++的单例模式与线程安全单例模式(懒汉/饿汉)

    下面小编就为大家带来一篇老生常谈C++的单例模式与线程安全单例模式(懒汉/饿汉)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • C++制作俄罗斯方块

    C++制作俄罗斯方块

    俄罗斯方块写过好几次了,每次的感觉都不一样,都有新的收获。就像达芬奇画鸡蛋一样,虽然都是画同样的鸡蛋,但是每次都有不同的收获。&nbsp;
    2016-05-05
  • C++小知识:不要节约代码行数

    C++小知识:不要节约代码行数

    今天小编就为大家分享一篇关于C++小知识:不要节约代码行数,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • C++模拟实现list功能

    C++模拟实现list功能

    list的底层是一个循环双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素,接下来通过本文给大家分享C++模拟实现list的示例代码,需要的朋友可以参考下
    2021-08-08
  • C语言中的pause()函数和alarm()函数以及sleep()函数

    C语言中的pause()函数和alarm()函数以及sleep()函数

    这篇文章主要介绍了C语言中的pause()函数和alarm()函数以及sleep()函数,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • C++跳转语句之Goto对变量定义的影响详解

    C++跳转语句之Goto对变量定义的影响详解

    goto语句也被称为无条件转移语句,这篇文章主要介绍了C++跳转语句之Goto对变量定义的影响,文中通过示例代码解文字介绍的很详细,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面跟着小编一起来学习学习吧。
    2016-11-11

最新评论