7.1 C/C++ 实现动态数组

c++,实现,动态,数组 · 浏览次数 : 35

小编点评

**动态数组** **定义:** 动态数组是一种内存动态分配的数组,其中数组大小在运行过程中被动态设置。 **主要功能:** * 创建和初始化动态数组。 * 添加元素到动态数组。 * 删除元素从动态数组。 * 遍历动态数组并输出元素的值。 **代码示例:** ```c #include "dynamic.h" struct DynamicArray { int *addr; int size; }; struct DynamicArray *InitDynamicArray(int size) { // 初始化动态数组 } void InsertDynamicArray(struct DynamicArray *ptr, int index, void *data) { // 将数据插入到指定位置 } void RemoveByPosDynamicArray(struct DynamicArray *ptr, int index) { // 从指定位置删除元素 } void RemoveByValueDynamicArray(struct DynamicArray *ptr, void *data, int (*compare)(void*, void *)) { // 在指定元素比较时删除元素 } void DestroyDynamicArray(struct DynamicArray *ptr) { // 释放动态数组内存 } void ForeachDynamicArray(struct DynamicArray *ptr, void (*callback)(void *data)) { // 遍历动态数组并执行回调函数 } ``` **使用说明:** 1. 创建一个 `DynamicArray` 结构,指定数组大小。 2. 使用 `InsertDynamicArray` 函数添加元素到动态数组。 3. 使用 `RemoveByPosDynamicArray` 和 `RemoveByValueDynamicArray` 函数删除元素。 4. 使用 `ForeachDynamicArray` 函数遍历动态数组并执行回调函数。 5. 使用 `DestroyDynamicArray` 函数释放动态数组内存。 **注意:** * 动态数组的大小必须在创建时指定。 * 遍历动态数组的顺序可能不同于添加元素的顺序。 * 使用的回调函数必须符合特定类型要求。

正文

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

动态数组的内存空间是从堆(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;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/f32bb5d5.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与7.1 C/C++ 实现动态数组相似的内容:

7.1 C/C++ 实现动态数组

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

7.2 C/C++ 实现动态链表

动态链表是一种常用的动态数据结构,可以在运行时动态地申请内存空间来存储数据,相比于静态数组和静态链表,更加灵活和高效。在动态链表中,数据元素被组织成一条链表,每个元素包含了指向下一个元素的指针,这样就可以通过指针将所有元素串联起来。使用动态链表存储数据时,不需要预先申请内存空间,而是在需要的时候才向内存申请。当需要添加新的元素时,可以使用`malloc`函数动态地申请内存空间,然后将新的元素插入到

7.5 C/C++ 实现链表队列

链表队列是一种基于链表实现的队列,相比于顺序队列而言,链表队列不需要预先申请固定大小的内存空间,可以根据需要动态申请和释放内存。在链表队列中,每个节点包含一个数据元素和一个指向下一个节点的指针,头节点表示队头,尾节点表示队尾,入队操作在队尾插入元素,出队操作在队头删除元素,队列的长度由节点数量决定。由于链表队列没有容量限制,因此可以处理任意数量的元素,但是相比于顺序队列,链表队列的访问速度较慢,因

7.3 C/C++ 实现顺序栈

顺序栈是一种基于数组实现的栈结构,它的数据元素存储在一段连续的内存空间中。在顺序栈中,栈顶元素的下标是固定的,而栈底元素的下标则随着入栈和出栈操作的进行而变化。通常,我们把栈底位置设置在数组空间的起始处,这样在进行入栈和出栈操作时,只需要维护栈顶指针即可。顺序栈的实现比较简单,它只需要一个数组和一个整型变量`top`即可。其中,数组用于存储栈中的元素,top则用于记录当前栈顶元素在数组中的位置。当

7.4 C/C++ 实现链表栈

相对于顺序栈,链表栈的内存使用更加灵活,因为链表栈的内存空间是通过动态分配获得的,它不需要在创建时确定其大小,而是根据需要逐个分配节点。当需要压入一个新的元素时,只需要分配一个新的节点,并将其插入到链表的头部;当需要弹出栈顶元素时,只需要删除链表头部的节点,并释放其所占用的内存空间即可。由于链表栈的空间利用率更高,因此在实际应用中,链表栈通常比顺序栈更受欢迎。在实现上,链表栈通过使用`malloc

像go 一样 打造.NET 单文件应用程序的编译器项目bflat 发布 7.0版本

现代.NET和C#在低级/系统程序以及与C/C++/Rust等互操作方面的能力完全令各位刮目相看了,有人用C#开发的64位操作系统: GitHub - nifanfa/MOOS: C# x64 operating system pro...,截图要介绍的是一个结合Roslyn和NativeAOT的实

5.1 C/C++ 使用文件与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

C++的extern关键字在HotSpot VM中的重要应用

extern关键字有两个用处: (1)extern在C/C++语言中表示函数和全局变量作用范围(可见性)的关键字,这个关键字会告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 (2)在C++中引用C语言中的函数和变量,在包含C语言头文件时,需要使用extern "C"来处理。 1、ext

【Azure 事件中心】Event Hub 无法连接,出现 Did not observe any item or terminal signal within 60000ms in 'flatMapMany' 的错误消息

2022-11-03 10:58:21.474 INFO --- [pool-7-thread-1] c.a.m.e.PartitionBasedLoadBalancer []: Load balancer already running 2022-11-03 10:58:51.014 WARN --- [ parallel-2] c.a.m.e.Partition

.NET周报 【7月第1期 2023-07-02】

## 国内文章 ### C# 实现 Linux 视频聊天、远程桌面(源码,支持信创国产化环境,银河麒麟,统信UOS) https://www.cnblogs.com/shawshank/p/17420469.html 园子里的有朋友在下载并了解了《[C# 实现 Linux 视频会议(源码,支持信创环