我有一个程序,该程序读取游戏内实体的“原始”列表,并且我打算制作一个持有不确定实体数量的索引号(int)的数组,以处理各种内容。我想避免使用过多的内存或CPU保留此类索引...

到目前为止,我使用的一个快速而肮脏的解决方案是在主处理功能(本地焦点)中声明具有最大游戏实体大小的数组,而另一个整数可以跟踪添加了多少次。这并不令人满意,因为每个列表都有3000多个阵列,这并不多,但是感觉像是浪费,因为我可能会将解决方案用于6-7个列表以进行不同的功能。

我还没有找到任何C(不是C ++或C#)特定解决方案来实现这一目标的。我可以使用指针,但是我有点害怕使用它们(除非这是唯一可能的方法)。

数组不会留下本地函数范围(如果将其传递给函数,然后丢弃),以防发生事物。

如果指针是唯一的解决方案,我该如何跟踪它们以避免泄漏?

有帮助吗?

解决方案

我可以使用指针,但我有点害怕使用它们。

如果您需要动态的数组,则无法逃脱指针。你为什么害怕?他们不会咬人(只要您小心,就是)。 C中没有内置的动态阵列,您只需要自己写一个即可。在C ++中,您可以使用内置 std::vector 班级。 C#和几乎所有其他高级语言也有一些类似的类,可以为您管理动态数组。

如果您确实打算编写自己的内容,那么以下是要使您开始的东西:大多数动态数组实现都可以从某些(小)默认大小的数组开始,那么每当您添加新元素时用完空间,请加倍数组的大小。正如您在下面的示例中看到的那样,这根本不是很困难:(我省略了安全检查)

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = (int *)malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = (int *)realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

使用它同样简单:

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%d\n", a.array[9]);  // print 10th element
printf("%d\n", a.used);  // print number of elements
freeArray(&a);

其他提示

我能想到一些选择。

  1. 链接列表。您可以使用链接列表来制作像事物一样动态增长的数组。但是你将无法做 array[100] 不必走 1-99 第一的。而且,您也可能没有那么方便。
  2. 大阵列。只需创建一个具有足够空间的数组
  3. 调整阵列。在知道大小和/或创建一个新数组时,每次用完空间并将所有数据复制到新数组时,都会重新创建数组。
  4. 链接列表阵列组合。只需使用带有固定尺寸的数组,一旦您用完了空间,就可以创建一个新数组并链接到该数组(明智的是跟踪数组和结构中下一个数组的链接)。

很难说在您的情况下哪种选择是最好的选择。当然,简单地创建大型阵列是最简单的解决方案之一,除非它真的很大,否则不应该给您太多问题。

就像一开始似乎比后来更可怕的一切一样,克服最初恐惧的最好方法是 沉浸在未知的不适感中呢毕竟,有时我们会学到最多学到的东西。

不幸的是,存在局限性。例如,当您仍在学习使用功能时,您不应该承担老师的角色。我经常阅读那些似乎不知道如何使用的人的答案 realloc (IE 当前接受的答案!)告诉他人如何错误地使用它,偶尔以他们的幌子 省略错误处理, ,即使这是一个常见的陷阱,需要提及。 这是解释如何使用的答案 realloc 正确. 请注意,答案将返回值存储到一个 不同的 变量以执行错误检查。

每次调用函数时,每次使用数组时,都使用指针。转化是隐式发生的,如果有什么东西甚至更可怕,因为我们看不到的事情通常会导致最大的问题。例如,内存泄漏...

数组操作员是指针操作员。 array[x] 真的是一个快捷方式 *(array + x), ,可以分解为: *(array + x). 。很可能是 * 就是让您感到困惑的原因。我们可以通过假设从问题中进一步消除该问题 x 成为 0, , 因此, array[0] 变成 *array 因为添加 0 不会更改值...

...因此我们可以看到 *array 等同于 array[0]. 。您可以使用一个要使用另一个的地方,反之亦然。数组操作员是指针操作员。

malloc, realloc 和朋友不 发明 您一直在使用的指针的概念;他们只是 采用 这实现了其他一些功能,这是一种不同形式的存储持续时间,最适合您在您想要的时候 大小的急剧变化.

当前接受的答案真是可惜 反对 其他一些关于Stackoverflow的非常有根据的建议, ,与此同时,错过了一个机会来引入一个鲜为人知的功能,该功能恰好为这个用户酶:灵活的阵列成员!那实际上是 很折断 回答... :(

当您定义您的 struct, ,声明您的数组 在末尾 结构,没有任何上限。例如:

struct int_list {
    size_t size;
    int value[];
};

这将使您团结起来 int 与您的分配相同 count, ,让他们这样束缚可能是 非常便利!

sizeof (struct int_list) 会好像 value 大小为0,所以它会告诉您结构的大小 带有空列表. 。您仍然需要添加到传递到的大小 realloc 指定列表的大小。

另一个方便的提示是记住 realloc(NULL, x) 等同于 malloc(x), ,我们可以使用它来简化我们的代码。例如:

int push_back(struct int_list **fubar, int value) {
    size_t x = *fubar ? fubar[0]->size : 0
         , y = x + 1;

    if ((x & y) == 0) {
        void *temp = realloc(*fubar, sizeof **fubar
                                   + (x + y) * sizeof fubar[0]->value[0]);
        if (!temp) { return 1; }
        *fubar = temp; // or, if you like, `fubar[0] = temp;`
    }

    fubar[0]->value[x] = value;
    fubar[0]->size = y;
    return 0;
}

struct int_list *array = NULL;

我选择使用的原因 struct int_list ** 由于第一个论点似乎并不明显,但是如果您考虑第二个论点,那么对 value 从内部 push_back 我们从我们打来的功能看不到吗?第一个参数也是如此,我们需要能够修改我们的 array, , 不只是 这里也许在任何其他功能中,我们都将其传递给...

array 开始什么都没有指向。这是一个空列表。 初始化 它与添加相同。例如:

struct int_list *array = NULL;
if (!push_back(&array, 42)) {
    // success!
}

PS 记得 free(array); 完成后!

当你说的时候

制作一个持有不确定数量实体数量的索引号(int)的数组

您基本上是在说您正在使用“指针”,但它是整个阵列范围内的本地指针,而不是整个内存的指针。由于您在概念上已经使用了“指针”(即指数组中的元素的ID号),所以为什么不使用常规指针(即涉及最大数组中元素的ID号:整个内存)。

您可以使它们代替存储一个指针,而不是存储资源ID号的对象。基本上是同一件事,但效率要高得多,因为我们避免将“ Array + Index”变成“指针”。

如果您认为它们是整个内存的数组索引(这就是它们实际上是什么),则指针不会令人恐惧

建立 Matteo Furlans 设计,当他说“大多数动态的数组实现通过从某些(小)默认大小的数组开始,然后在添加新元素时用完空间,将数组的大小翻倍“。工作正在进行中“以下是它的尺寸并不是两倍,它旨在仅使用所需的内容。我还省略了安全检查以实现简单性...也构建 Brimboriums 想法,我试图将删除函数添加到代码...

存储.h文件看起来像这样...

#ifndef STORAGE_H
#define STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct 
    {
        int *array;
        size_t size;
    } Array;

    void Array_Init(Array *array);
    void Array_Add(Array *array, int item);
    void Array_Delete(Array *array, int index);
    void Array_Free(Array *array);

#ifdef __cplusplus
}
#endif

#endif /* STORAGE_H */

storage.c文件看起来像这样...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

/* Initialise an empty array */
void Array_Init(Array *array) 
{
    int *int_pointer;

    int_pointer = (int *)malloc(sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to allocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
        array->size = 0;
    }
}

/* Dynamically add to end of an array */
void Array_Add(Array *array, int item) 
{
    int *int_pointer;

    array->size += 1;

    int_pointer = (int *)realloc(array->array, array->size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer;
        array->array[array->size-1] = item;
    }
}

/* Delete from a dynamic array */
void Array_Delete(Array *array, int index) 
{
    int i;
    Array temp;
    int *int_pointer;

    Array_Init(&temp);

    for(i=index; i<array->size; i++)
    {
        array->array[i] = array->array[i + 1];
    }

    array->size -= 1;

    for (i = 0; i < array->size; i++)
    {
        Array_Add(&temp, array->array[i]);
    }

    int_pointer = (int *)realloc(temp.array, temp.size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
    } 
}

/* Free an array */
void Array_Free(Array *array) 
{
  free(array->array);
  array->array = NULL;
  array->size = 0;  
}

main.c看起来像这样...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

int main(int argc, char** argv) 
{
    Array pointers;
    int i;

    Array_Init(&pointers);

    for (i = 0; i < 60; i++)
    {
        Array_Add(&pointers, i);        
    }

    Array_Delete(&pointers, 3);

    Array_Delete(&pointers, 6);

    Array_Delete(&pointers, 30);

    for (i = 0; i < pointers.size; i++)
    {        
        printf("Value: %d Size:%d \n", pointers.array[i], pointers.size);
    }

    Array_Free(&pointers);

    return (EXIT_SUCCESS);
}

期待 有建设性的批评 跟随...

创建一系列任何类型的无限项目:

typedef struct STRUCT_SS_VECTOR {
    size_t size;
    void** items;
} ss_vector;


ss_vector* ss_init_vector(size_t item_size) {
    ss_vector* vector;
    vector = malloc(sizeof(ss_vector));
    vector->size = 0;
    vector->items = calloc(0, item_size);

    return vector;
}

void ss_vector_append(ss_vector* vec, void* item) {
    vec->size++;
    vec->items = realloc(vec->items, vec->size * sizeof(item));
    vec->items[vec->size - 1] = item;
};

void ss_vector_free(ss_vector* vec) {
    for (int i = 0; i < vec->size; i++)
        free(vec->items[i]);

    free(vec->items);
    free(vec);
}

以及如何使用它:

// defining some sort of struct, can be anything really
typedef struct APPLE_STRUCT {
    int id;
} apple;

apple* init_apple(int id) {
    apple* a;
    a = malloc(sizeof(apple));
    a-> id = id;
    return a;
};


int main(int argc, char* argv[]) {
    ss_vector* vector = ss_init_vector(sizeof(apple));

    // inserting some items
    for (int i = 0; i < 10; i++)
        ss_vector_append(vector, init_apple(i));


    // dont forget to free it
    ss_vector_free(vector);

    return 0;
}

该向量/数组可以容纳任何类型的项目,并且大小完全动态。

好吧,我想如果您需要删除元素,您将制作鄙视要排除的元素的数组的副本。

// inserting some items
void* element_2_remove = getElement2BRemove();

for (int i = 0; i < vector->size; i++){
       if(vector[i]!=element_2_remove) copy2TempVector(vector[i]);
       }

free(vector->items);
free(vector);
fillFromTempVector(vector);
//

假使,假设 getElement2BRemove(), copy2TempVector( void* ...)fillFromTempVector(...) 是处理温度向量的辅助方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top