【问题标题】:An array that increases in size as a loop continues C一个随着循环继续而增大的数组 C
【发布时间】:2014-06-25 20:03:55
【问题描述】:

我正在尝试生成一个随着 while 循环迭代而增大的数组。我知道指针与解决方案有关。请看下面的代码。

#include <stdio.h>

int main () {

  int x = 0;
  int *F = malloc(sizeof(int)); //I want F to start out as :- 
  F[0] = 1;                     // 1 by 1
  F[1] = 2;                     // 1 by 2 such that it increases in size when assigned
  int now = 2;

  int evenSum = 2;

  while (x <= 40000) {


    F[now] = F[now-1] + F[now-2];
    x = F[now];

    if (F[now] % 2)
    {
        evenSum += F[now];
    }

    ++now;
  }

  printf("The outcome is %d\n", evenSum);

  //free(F);
  // Yes this is problem 2 of euler challenge, i already got a working static model

}

提前致谢

编辑 我实际上正在寻找的是所有偶数 fib 的总和,直到 40M 的截止限制。当我在 fib 序列中遇到偶数时,我可以(我第一次做的)求和。这意味着我没有保留一些任意大小的数组。这篇文章的目的是创建一个不断增长的内存,它会不断消耗内存,直到找到答案。 以下是我从给出的精彩答案中得到的代码。

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

struct vector {
    size_t size;
    int *data;
};

void vector_resize(struct vector *vector, size_t size) {
    if (vector->size >= size)
        return;
    while (vector->size < size)
        vector->size *= 2;
    vector->data = realloc(vector->data, sizeof(int) * vector->size);
    assert(vector->data != NULL);
}

struct vector * vector_init() {
    struct vector *vector = malloc(sizeof(*vector));
    vector->size = 4;
    vector->data = malloc(vector->size * sizeof(int));
    return vector;
}

void vector_free(struct vector *vector) {
    free(vector->data);
    free(vector);
}

void vector_put(struct vector *vector, size_t index, int data) {
    vector_resize(vector, index+1);
    vector->data[index] = data;;
}

int vector_get(struct vector *vector, size_t index) {
    vector_resize(vector, index+1);
    return vector->data[index];
}

int main() {
    struct vector *vector = vector_init();

    int fibNow = 0;

    int now = 2;
    vector_put(vector, 0, 1);
    vector_put(vector, 1, 2);

    int evenSum = 2;

    while (fibNow <= 4000000) {
        fibNow = vector_get(vector, (now-1)) + vector_get(vector, (now-2));
        vector_put(vector, now, fibNow);

        if (fibNow % 2 == 0) {
            evenSum += fibNow;
        }

        ++now;
    }
    printf("The outcome is %d\n", evenSum);

    // vector_put(vector, 0, 5);
    // vector_put(vector, 9, 2);
    // int i;
    // for (i=0; i<10; ++i)
    //     printf("index 0: %d\n", vector_get(vector, i));
    vector_free(vector);
}

【问题讨论】:

  • 你可以用malloc(sizeof(int) * NUMELEMENTS)在堆上分配一个数组。查看realloc 为您的扩展数组重新分配足够的空间。
  • 使用realloc,但在这种情况下,您不妨一次性分配整个数组并省去您的麻烦(或者更好的是,只使用几个ints,因为您只需要在任何给定时间跟踪序列中不超过三个数字和当前总和)。
  • 我想要内存中的 fib 数字的完整列表,这样我可以在以后操作它们。 40K 以下的 fib 数字的 evenSum 是即时生成的,我不想存储它。
  • 关于此代码:int F = malloc(sizeof(int)); //我希望 F 开始为:- F[0] = 1; // 1乘1 F[1] = 2;由于代码仅为 int 分配单个区域,因此 f[1] 正在破坏堆(malloc 从中分配其区域)。因此,代码操作在 'F[1] = 2' 处未定义之后的任何操作都只是运气问题。作为初始修复,建议为至少 3 个 int 的 IE 分配足够的空间 int *F = (int)malloc(sizeof(int)*3);
  • 这一行:++now;结果为: F[now] = F[now-1] + F[now-2];逐渐破坏越来越多的堆。

标签: arrays pointers dynamic linked-list malloc


【解决方案1】:

因此,在 C 语言中,我们不允许重载 operator[]。但我们仍然可以创建一个功能类似于您的请求的对象:

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

struct vector {
    size_t size;
    int *data;
};

void vector_resize(struct vector *vector, size_t size) {
    if (vector->size >= size)
        return;
    while (vector->size < size)
        vector->size *= 2;
    vector->data = realloc(vector->data, sizeof(int) * vector->size);
    assert(vector->data != NULL);
}

struct vector * vector_init() {
    struct vector *vector = malloc(sizeof(*vector));
    vector->size = 4;
    vector->data = malloc(vector->size * sizeof(int));
    return vector;
}

void vector_free(struct vector *vector) {
    free(vector->data);
    free(vector);
}

void vector_put(struct vector *vector, size_t index, int data) {
    vector_resize(vector, index+1);
    vector->data[index] = data;;
}

int vector_get(struct vector *vector, size_t index) {
    vector_resize(vector, index+1);
    return vector->data[index];
}

int main() {
    struct vector *vector = vector_init();

    vector_put(vector, 0, 5);
    vector_put(vector, 9, 2);

    for (int i=0; i<10; ++i)
        printf("index 0: %d\n", vector_get(vector, i));

    vector_free(vector);
}

此外,看看 C++ 版本的这可能是什么很有趣。 C++ 使这看起来更像您的原始代码,因为我们可以为任意对象重载 operator[]。

#include <cstdio>
#include <vector>

template <typename T>
class auto_growing_vector {
    private:
        std::vector<T> data;

    public:
        T & operator[](size_t index) {
            if (index >= data.size())
                data.resize(index + 1);
            return data[index];
        }
};

int main() {
    auto_growing_vector<int> vector;

    vector[0] = 5;
    vector[9] = 2;

    for (int i=0; i<10; ++i)
        printf("index 0: %d\n", vector[i]);
}

【讨论】:

  • 为什么需要重载 [] 运算符来执行此操作?在 C 中允许使用 a[i],其中“a”是指向任意内存位置的任意类型指针,“i”是偏移位置的整数,用于 i*sizeof(指针的类型)所以 a[ i] *(a+i) 谢谢 :)
  • @ETFovac:很抱歉,我无法理解您的问题。请注意,在 C 代码中,vector_put() 不仅仅是 return data[i],在 C++ 代码中,operator[]() 也不仅仅是 return data[i]。此外,请注意 auto_growing_vector 是 C++ 对象,而不是数组。
  • @ETFovac OP 指定他希望 a[i] 重新分配 a 以便 a[i] 不是越界访问
  • 我误解了你所说的。现在好了。 :)
  • 这正是我想要的,也称为Linked Lists
【解决方案2】:

一般来说,realloc 应该可以为您解决问题。示例(这只是一个 sn-p - 您需要自己完成其余的工作):

int *F;
F = malloc(2 * sizeof *F); // note you have to start with 2 elements for your code, not 1
F[0] = 1;
F[1] = 2;
// when you know you need to increase the size of F:
temp = realloc(F, n * sizeof *F); // where n is the new size in elements
if(temp != NULL) F = temp; // note that the block may have moved to a new place!
else {
  printf("unable to grow the array to %d elements!\n", n);
  free(F);
  exit(0);
}

当然,对于这个问题,您不需要保留所有斐波那契数 - 只需保留最后两个。这实际上暗示了一个更简单的代码。让我为你开始,看看你能不能完成它(因为你正在做欧拉问题,这都是关于自己解决的问题):

int first = 1;
int second = 1; // usually you start with 1,1,2,3,...
int temp, current;
int count;
int N = 4000; // where we stop

for(count = 2; count < N; count ++) {
  current = first + second;
  first = second;
  second = current;
}

如果你仔细观察,你可以得到比这个更有效的(提示,你真的只需要保留一个旧值,而不是两个......)

读取 cmets,如果你想要内存中的所有数字,你应该从一开始就分配足够的空间:

F = malloc(4000 * sizeof *F); 

并且不需要进一步的操作。在这种情况下,请确保您的最后一个索引是 3999(因为数组的索引为零)。

【讨论】:

  • 我有一个可以工作的静态模型,这个实验的全部目的是创建一个函数,该函数会一直运行直到满足 while 语句。我认为就效率而言,您所暗示的类似于current = current + previous; previous = current - previous;
  • 我现在明白了——你不是在寻找第 n 个 Fib 数字,而是第一个比什么都大的数字。实际上,您可以从 F(n) ~ phi^n / sqrt(5) 中获得斐波那契数的大小的一个很好的近似值,其中 phi = 1.618033... 所以要获得大于 N 的斐波那契数,您需要分配大约log(sqrt(5)*N)/log(phi) 元素。再加上 10 分,你几乎肯定是不错的。
  • 我不知道那是数学黑客。谢谢你给我看。我实际上正在寻找的是所有偶数 fib 的总和,直到 40K 的截止限制。当我在 fib 序列中遇到偶数时,我可以(我第一次做的)求和。这意味着我没有保留一些任意大小的数组。这篇文章的目的是创建一个不断增长的内存,它会不断消耗内存直到找到答案。
【解决方案3】:

I 一种方法是使用 2D 数组 int[n][n],其中有很多未使用的空间

II 更简单的方法是通过重新分配函数在每次迭代中扩展数组大小。 在这种情况下,要么:

a) 原始数组的每个元素都将是一个指向长度为 i 的新数组的指针(i beeing 迭代次数),然后您将重新分配原始数组以使新指针的大小,然后分配 i*sizeof(int ) 为指针指向的新数组分配新内存。

b) 您将制作线性化训练矩阵,其中原始数组将仅包含数字,而不是指针。在每次迭代中,您都会为 i 个新元素扩展它的大小。线性化三角矩阵是一维数字数组,其中数据保存如下:

ordinary matrix: (/ = wasted memory)
A/// 
BC//
DEF/
GHIJ

linarized triangular matrix
ABCDEFGHIJ

您可以使用坐标 [y,x] = [2,1](元素“A”作为原点)访问线性化三角矩阵元素 E,例如

sum=0;
for(iy=0;iy<y;iy++)
  for(ix=0;ix<=y && ix<x;ix++) sum++;
//myLinMatr[sum]=='E'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2021-12-19
    • 2014-06-12
    • 2014-07-21
    • 1970-01-01
    相关资源
    最近更新 更多