恢复具有多个索引范围的大型数组的元素

时间:2018-05-27 17:00:29

标签: c arrays indexing

这是一个棘手的问题,我一直在思考这个问题,并且还没有在任何地方看到令人满意的答案。假设我有一个大小为10000的大型int数组。我可以用以下方式声明它:

 int main()
{

    int foo[10000];

    int i;
    int n;
    n = sizeof(foo) / sizeof(int);

    for (i = 0; i < n; i++)
    {
        printf("Index %d is %d\n",i,foo[i] );
    }

    return 0;
}

很明显,在我正式初始化数组之前,数组中的每个索引都会包含一组随机的数字:

Index 0 is 0
Index 1 is 0
Index 2 is 0
Index 3 is 0
   .
   .
   .
Index 6087 is 0
Index 6088 is 1377050464
Index 6089 is 32767
Index 6090 is 1680893034
   .
   .
   .
Index 9996 is 0
Index 9997 is 0
Index 9998 is 0
Index 9999 is 0

然后假设我初始化我的数组的选择索引范围,其值保存整个程序的特定值并且必须保留,目的是为后续传递这些值操作某些功能:

//Call this block 1
foo[0] = 0;
foo[1] = 7;
foo[2] = 99;
foo[3] = 0;

//Call this block 2
foo[9996] = 0;
foo[9997] = 444;
foo[9998] = 2;
foo[9999] = 0;

for (i = 0; i < (What goes here?); i++)
{
    //I must pass in only those values initialized to select indices of foo[] (Blocks 1 and 2 uncorrupted)

    //How to recover those values to pass into foo_func()?

    foo_func(foo[]);
}

在我自己正式初始化数组之前,我初始化foo[]的一些值与数组中预先存在的值重叠。如果有多个索引范围,我怎样才能传入我初始化的数组元素的索引?我无法解决这个问题。感谢您的帮助!

编辑:

我还应该提一下,数组本身将从.txt文件中读取。为了说明的目的,我只是在代码中展示了初始化。

2 个答案:

答案 0 :(得分:1)

有许多方法可以在初始化时或之后快速将阵列中的内存清零。

对于堆栈上的数组,用零初始化它。 {0}是简写。

int foo[10000] = {0};

对于堆上的数组,使用calloc分配内存并使用0&#39进行初始化。

int *foo = calloc(10000, sizeof(int));

如果阵列已存在,请使用memset快速用零覆盖所有阵列的内存。

memset(foo, 0, sizeof(int) * 10000);

现在所有元素都为零。您可以逐个将各个元素设置为您喜欢的任何元素。例如......

int main() {
    int foo[10] = {0};

    foo[1] = 7;
    foo[2] = 99;
    foo[7] = 444;
    foo[8] = 2;

    for( int i = 0; i < 10; i++ ) {
        printf("%d - %d\n", i, foo[i]);
    }
}

那会打印......

0 - 0
1 - 7
2 - 99
3 - 0
4 - 0
5 - 0
6 - 0
7 - 444
8 - 2
9 - 0

作为旁注,仅使用大型数组的少数元素是浪费内存。相反,使用hash table,或者如果您需要订购,请使用某种类型的tree。这些可能很难正确实现,但a library such as GLib can provide you with good implementations

答案 1 :(得分:0)

简介

我对您的问题做出了强有力的假设,它是稀疏性(数组中的大多数元素将保持为零)。 根据这个假设,我会将数组构建为列表。我包含一个示例代码,它不完整而且不打算 是---你应该做自己的功课:)。

核心对象是一个带有指向begin元素和大小的指针的结构:

typedef struct vector {
  size_t size;
  vector_element_t * begin;
} vector_t;

向量的每个元素都有自己的索引和值以及指向列表中下一个元素的指针:

typedef struct vector_element vector_element_t;
struct vector_element {
  int value;
  size_t index;
  vector_element_t *next;
};

在此基础上我们可以通过在排序上删除约束来构建动态向量作为列表(不需要,你可以修改此代码 使用一些简单的自定义方法来维护订购:

vector_t * vector_init(); // Initialize an empty array
void vector_destroy(vector_t* v); // Destroy the content and the array itself
int vector_get(vector_t *v, size_t index); // Get an element from the array, by searching the index
size_t vector_set(vector_t *v, size_t index, int value); // Set an element at the index
void vector_delete(vector_t *v, size_t index); // Delete an element from the vector
void vector_each(vector_t *v, int(*f)(size_t index, int value)); // Executes a callback for each element of the list
                                                                 // This last function may be the response to your question

Test it online

主要例子

这是一个使用所有这些方法并在控制台中打印的主要内容:

int callback(size_t index, int value) {
  printf("Vector[%lu] = %d\n", index, value);
  return value;
}

int main() {
  vector_t * vec = vector_init();

  vector_set(vec, 10, 5);
  vector_set(vec, 23, 9);
  vector_set(vec, 1000, 3);

  printf("vector_get(vec, %d) = %d\n", 1000, vector_get(vec, 1000)); // This should print 3
  printf("vector_get(vec, %d) = %d\n", 1, vector_get(vec, 1)); // this should print 0
  printf("size(vec) = %lu\n", vec->size); // this should print 3 (the size of initialized elements)

  vector_each(vec, callback); // Calling the callback on each element of the
                              // array that is initialized, as you asked.

  vector_delete(vec, 23);
  printf("size(vec) = %lu\n", vec->size);
  vector_each(vec, callback); // Calling the callback on each element of the array

  vector_destroy(vec);
  return 0;
}

输出:

vector_get(vec, 1000) = 3
vector_get(vec, 1) = 0
size(vec) = 3
Vector[10] = 5
Vector[23] = 9
Vector[1000] = 3
size(vec) = 3
Vector[10] = 5
Vector[1000] = 3

具有[{1}}功能的callback是您真正应该关注的内容。

实现

我在介绍中为您提供了一些简单的实现。他们不完整, 应该引入对指针的一些检查。我把它留给你了。实际上,此代码不适用于生产,在某些情况下也可能会溢出

特定部分是在向量中搜索特定元素。每次你翻转清单, 这只是方便的,只有当你有稀疏性时(你的索引的大部分总是会返回零)。 在此实现中,如果您访问未登记的索引,则会得到0.如果您不想要这个 你应该定义一个错误回调。

初始化和销毁​​

初始化时,我们为向量分配内存,但内部没有元素,因此vector_each指向begin。当我们破坏向量时,我们不仅要释放向量,还要释放每个元素。

NULL

get和set方法

在get中你可以看到列表是如何工作的(和相同的概念 也用于set和delete):我们从begin开始,然后 我们越过列表,直到我们到达索引相等的元素 要求的那个。如果我们找不到它,我们只返回0。 如果我们需要提出某种信号&#34;当值是 没有找到,很容易实现&#34;错误回调&#34;。

只要稀疏成立,在整个数组中搜索索引就内存需求而言是一个很好的折衷方案,效率可能不是问题。

vector_t * vector_init() {
  vector_t * v = (vector_t*)malloc(sizeof(vector_t));
  if (v) {
    v->begin = NULL;
    v->size = 0;
    return v;
  }
  return NULL;
}

void vector_destroy(vector_t *v) {
  if (v) {
    vector_element_t * curr = v->begin;
    if (curr) {
      vector_element_t * next = curr->next;
      while (next) {
        curr = curr->next;
        next = next->next;
        if (curr)
          free(curr);
      }
      if (next)
        free(next);
    }
    free(v);
  }
}

删除元素

通过这种方法,可以非常容易地删除元素,连接 int vector_get(vector_t *v, size_t index) { vector_element_t * el = v->begin; while (el != NULL) { if (el->index == index) return el->value; el = el->next; } return 0; } // Gosh, this set function is really a mess... I hope you can understand it... // -.-' size_t vector_set(vector_t *v, size_t index, int value) { vector_element_t * el = v->begin; // Case 1: Initialize the first element of the array if (el == NULL) { el = (vector_element_t *)malloc(sizeof(vector_element_t)); if (el != NULL) { v->begin = el; v->size += 1; el->index = index; el->value = value; el->next = NULL; return v->size; } else { return 0; } } // Case 2: Search for the element in the array while (el != NULL) { if (el->index == index) { el->value = value; return v->size; } // Case 3: if there is no element with that index creates a new element if (el->next == NULL) { el->next = (vector_element_t *)malloc(sizeof(vector_element_t)); if (el->next != NULL) { v->size += 1; el->next->index = index; el->next->value = value; el->next->next = NULL; return v->size; } return 0; } el = el->next; } } curr->next。我们必须释放之前的curr->next->next ...

curr->next

迭代函数

我认为这是你问题最后部分的答案, 而是传递一系列索引,您将回调传递给向量。 回调获取并设置特定索引中的值。如果你想 只对某些特定索引进行操作,您可以在中查看 回调本身。如果您需要将更多数据传递给回调,请检查 最后一节。

void vector_delete(vector_t * v, size_t index) {
  vector_element_t *curr = v->begin;
  vector_element_t *next = curr->next;

  while (next != NULL) {
    if (next->index == index) {
      curr->next = next->next;
      free(next);
      return;
    } else {
      curr = next;
      next = next->next;
    }
  }
}

错误回调

您可能想要提出一些越界错误或其他内容。一种解决方案是使用函数指针丰富您的列表,该函数指针表示当您的用户sk为未定义的元素时应该调用的回调:

void vector_each(vector_t * v, int (*f)(size_t index, int value)) {
  vector_element_t *el = v->begin;
  while (el) {
    el->value = f(el->index, el->value);
    el = el->next;
  }
}

也许在您的typedef struct vector { size_t size; vector_element_t *begin; void (*error_undefined)(vector *v, size_t index); } vector_t 功能结束时,您可能需要执行以下操作:

vector_get

通常还可以添加辅助函数来设置回调...

将用户数据传递给&#34;每个&#34;回调

如果要将更多数据传递给用户回调,可以添加int vector_get(vector_t *v, size_t index) { // [ . . .] // you know at index the element is undefined: if (v->error_undefined) v->error_undefined(v, index); else { // Do something to clean up the user mess... or simply return 0; } } 作为最后一个参数:

void*

如果用户不需要,他可以传递一个精彩的void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data)); void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data)) { [...] el->value = f(el->index, el->value, user_data); [...] }