【问题标题】:C Vector/ArrayList/LinkedListC 向量/ArrayList/LinkedList
【发布时间】:2011-01-15 20:14:12
【问题描述】:

我正在用 C 编写一个小程序,我需要一种向量/ArrayList/LinkedList,但我正在使用 C。知道如何在 C 中做这种事情吗?

我想存储结构,然后追加/删除一些。

【问题讨论】:

  • 标准 C 库中没有这样的东西。人们通常自己动手。
  • 虽然术语向量和 ArrayList 通常指的是相同的数据结构(可调整大小的数组),但链表是完全不同的东西。那么你想要一个可调整大小的数组还是一个链表?
  • 人们不应该这样做。 Glib 在这里有一个非常好的实现:library.gnome.org/devel/glib/unstable/… 大多数 Unix C 库都包含一个 tsearch 的实现,虽然使用起来很尴尬,但可以作为元素列表被压入服务。
  • @Michiel:为什么不将其发布为答案而不是评论?
  • 考虑到 OP 听起来像个初学者,我建议他先推出自己的解决方案,但也有经过测试和验证的实现可用。

标签: c


【解决方案1】:

对于可调整大小的数组,您可以使用malloc()realloc()。这些允许您在堆上保留(使用malloc())和调整(使用realloc())一定数量的空间。它们是这样使用的:

int* a = malloc(10 * sizeof(int));

if(a == NULL) {}     // malloc() was unable to allocate the memory, handle the
                     // error and DO NOT use this pointer anymore

// now you can treat a as a normal array of 10 ints:
a[4] = 51;

// suppose 10 ints aren't no more enough:
a = realloc(a, 20 * sizeof(int));

if(a == NULL) {}     // same thing as before

// here you have 20 ints, the previous 10 are still there
a[18] = a[4]

// don't forget to free the memory when you have finished:
free(a);

只需将 'int' 替换为您的结构类型。 ;)

【讨论】:

  • 由于问题仅用“C”标记,因此是否应该用不必要的(和丑陋的!)弊大于利的强制转换(例如,通过隐藏错误)来填充示例是值得怀疑的。投射到void* 可以说是从不的好习惯!此外,错误处理很重要,因为没有异常,您必须检查 mallocrealloc 的返回值(并且不要丢失原始指针!)此外,对 realloc 的调用不会增加几乎任何计算机上的缓冲区大小(20 个字节非常很少超过 10 个整数)。
  • 此外,您必须更改的不仅仅是强制转换,才能使其与其他类型一起使用。但是,如果您遵循更好的样式(即 type *ptr = malloc(N * sizeof *ptr)realloc 类似),您只需要在声明中更改类型 type
  • 不引入 free() 就不能引入 malloc() 和 realloc()
  • @eq:我忘记了 realloc() 中的 sizeof(int)。 ;) 现在好点了吗?
  • @user576488:操作系统将占用它为您的程序提供的所有内存,因此不要 free() 不会杀死任何人,但最好这样做。
【解决方案2】:

使用现有的实现。有数十亿。 Glib 可能是一个不错的起点,或者LibH

【讨论】:

    【解决方案3】:

    我使用了@Conrad Meyer 的回答。从here 下载最新的Glib 库并使用this 手册编译它。为了测试 Glib 库,我使用了 this 测试。编译测试代码时可能会出错。 This 会帮你解决问题。

    我还发现测试代码中存在某种内存泄漏。 Valgrind 运行原代码的结果:

    ==20350== HEAP SUMMARY:
    ==20350==     in use at exit: 4,632 bytes in 12 blocks
    ==20350==   total heap usage: 12 allocs, 0 frees, 4,632 bytes allocated
    ==20350== 
    ==20350== LEAK SUMMARY:
    ==20350==    definitely lost: 0 bytes in 0 blocks
    ==20350==    indirectly lost: 0 bytes in 0 blocks
    ==20350==      possibly lost: 992 bytes in 4 blocks
    ==20350==    still reachable: 3,640 bytes in 8 blocks
    ==20350==         suppressed: 0 bytes in 0 blocks
    

    所以我在代码中插入了一行:

    #include <stdio.h>
    #include <glib.h>
    
    int main(int argc, char** argv) {
        GList* list = NULL;
        list = g_list_append(list, "Hello world!");
        printf("The first item is '%s'\n", (char *)g_list_first(list)->data);
        g_list_free(list);
        return 0;
    }
    

    Valgrind 新结果:

    ==20310== HEAP SUMMARY:
    ==20310==     in use at exit: 4,632 bytes in 12 blocks
    ==20310==   total heap usage: 12 allocs, 0 frees, 4,632 bytes allocated
    ==20310== 
    ==20310== LEAK SUMMARY:
    ==20310==    definitely lost: 0 bytes in 0 blocks
    ==20310==    indirectly lost: 0 bytes in 0 blocks
    ==20310==      possibly lost: 0 bytes in 0 blocks
    ==20310==    still reachable: 4,632 bytes in 12 blocks
    ==20310==         suppressed: 0 bytes in 0 blocks
    

    This 的回答告诉我们不用担心still reachable 的内存问题。

    【讨论】:

      【解决方案4】:

      C 不附带任何形式的标准集合(与 C++ 和 Java 等高级语言不同),因此您有几个选择:

      1. 使用由某个团体/某个个人创建的现有的(如上所述)
      2. 创建自己的

      您需要准确考虑该程序需要什么来确定您使用什么。根据您的要求,您可能正在寻找以下两种选择之一:

      1. 分配后会动态增长的数组。本质上,您需要维护此时数组中包含多少元素。如果在插入过程中的任何时候超过最大数量的元素,则必须创建一个新数组,将元素复制到新数组中,插入新元素,最后删除旧数组。这在访问时间方面往往更快(因为它是可索引的),但如果您过度分配,则会变得缓慢且消耗内存。有关示例,请参见 BlackBear 的代码。
      2. 按设计动态增长的链表。见这里:http://en.wikipedia.org/wiki/Linked_list#Singly-.2C_doubly-.2C_and_multiply-linked_lists。这样做的主要优点是在特殊情况下无需额外维护,但缺点是访问速度慢(查看每个元素,直到找到所需的元素)。

      有关这两种数据结构之间权衡的更多信息,请参阅 Wikipedia 页面。

      【讨论】:

      • 每次添加都会重新分配是否会受到影响?
      • @user576488:速度很慢。您可以声明数组留下一些未使用的空间,以防您以后需要它
      • 重新分配让我们说 10 块?会更好吗?
      • @user576488:是的。越大越好
      • @user576488:重新分配的常见策略是算术增长(即添加固定数量的元素)和几何增长(即将大小乘以固定因子,例如将大小加倍)
      猜你喜欢
      • 2011-08-16
      • 2017-10-24
      • 1970-01-01
      • 1970-01-01
      • 2012-03-24
      • 2017-10-20
      • 2014-06-08
      • 1970-01-01
      • 2023-03-09
      相关资源
      最近更新 更多