#arrays #pointers #dynamic #linked-list #malloc
#массивы #указатели #динамический #связанный список #malloc
Вопрос:
Я пытаюсь сгенерировать массив, размер которого увеличивается по мере выполнения цикла 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 %dn", 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 %dn", evenSum);
// vector_put(vector, 0, 5);
// vector_put(vector, 9, 2);
// int i;
// for (i=0; i<10; i)
// printf("index 0: %dn", vector_get(vector, i));
vector_free(vector);
}
Комментарии:
1. Вы можете выделить массив в куче с
malloc(sizeof(int) * NUMELEMENTS)
помощью . Проверьте,realloc
чтобы перераспределить достаточно места для вашего расширяющегося массива.2. Используйте
realloc
, хотя в этом случае вы могли бы просто выделить весь массив за один раз и избавить себя от головной боли (или, что еще лучше, используйте всего несколькоint
секунд, поскольку вам нужно отслеживать не более трех чисел в последовательности и текущую сумму в любой момент времени).3. Мне нужен полный список номеров fib в памяти, чтобы я мог манипулировать ими позже. Четная сумма для чисел fib менее 40 КБ генерируется «на лету», и у меня нет желания хранить это.
4. что касается этого кода: int F = malloc(sizeof(int)); //Я хочу, чтобы F начинался как:- F[0] = 1; // 1 на 1 F[1] = 2; Поскольку код содержит только одну область для int, значениеf[1] повреждает кучу (из которой malloc выделил свою область. Следовательно, действие кода не определено в ‘F [1] = 2’, и любое действие после этого является лишь вопросом удачи. В качестве первоначального исправления предложите, чтобы в malloc было достаточно места как минимум для 3 int, т.Е. int *F = (int )malloc(sizeof(int)*3);
5. эта строка: now; приводит к строке: F[now] = F[now-1] F [now-2]; постепенно повреждая все больше и больше кучи.
Ответ №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: %dn", 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 amp; 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: %dn", vector[i]);
}
Комментарии:
1. Зачем вам перегружать оператор [] для этого? В C разрешено использовать a[i], где ‘a’ — указатель произвольного типа на произвольную ячейку памяти, а ‘i’ — целое число, которое смещает местоположение для i*sizeof(тип указателя), так что a[i] <=> *(a i) Спасибо 🙂
2. @ETFovac: Извините, я не могу понять ваш вопрос. Обратите внимание, что в коде C
vector_put()
делает больше, чем простоreturn data[i]
, и в коде Coperator[]()
также делает больше, чем простоreturn data[i]
. Кроме того, обратите внимание, чтоauto_growing_vector
это объект C , а не массив.3. @ETFovac OP указал, что он хочет
a[i]
перераспределитьa
, чтобы этоa[i]
не был доступ за пределы4. Я неправильно понял, что вы сказали. Теперь все в порядке. 🙂
5. Это именно то, что я хотел, также известный как связанные списки
Ответ №2:
В общем, realloc
это должно сработать за вас. Пример (это всего лишь фрагмент — остальное вам нужно будет сделать самостоятельно):
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;
}
Если вы присмотритесь, вы можете стать еще более эффективным, чем это (подсказка, вам действительно нужно сохранить только одно старое значение, а не два …)
Читая комментарии, если вы хотите, чтобы все числа были в памяти, вы должны просто выделить достаточно места с самого начала:
F = malloc(4000 * sizeof *F);
и никаких дальнейших манипуляций не требуется. Убедитесь, что в этом случае ваш последний индекс равен 3999 (поскольку массивы индексируются с нулевым индексом).
Комментарии:
1. У меня есть рабочая статическая модель, вся цель этого эксперимента заключалась в создании функции, которая просто продолжает работать до тех пор, пока не будет выполнен оператор while . Я полагаю, что в отношении эффективности, на что вы намекаете, это что-то вроде
current = current previous; previous = current - previous;
2. Теперь я вижу, что вы ищете не n-е число Fib, а первое число, большее чего-то. На самом деле вы можете получить хорошее приближение размера числа Фибоначчи из F(n) ~ phi ^ n / sqrt(5), где phi = 1,618033… итак, чтобы получить число Фибоначчи больше N, вам нужно выделить около log(sqrt(5) * N) / log(phi) элементов. Добавьте дополнительные 10 для хорошей оценки, и у вас почти наверняка все получится.
3. Я не знал, что это математический взлом. Спасибо, что показали мне. То, что я на самом деле ищу, — это сумма всех четных значений fib до предельного значения 40 Тыс. Я мог бы (что я сделал в первый раз) суммировать четные числа по мере их появления во время последовательности fib. Это означало, что я не сохранил массив некоторого произвольного размера. Цель этого сообщения — создать растущую память, которая просто продолжает потреблять память, пока не дойдет до ответа.
Ответ №3:
Одним из способов было бы использовать 2D-массив int[n][n] с большим количеством неиспользуемого пространства
II Более простым способом было бы увеличивать размер массива на каждой итерации с помощью функции realocate . Только в этом случае либо:
a) каждый элемент исходного массива будет указателем на новый массив длиной i (i — номер итерации), затем вы должны изменить местоположение исходного массива, чтобы сделать размер для нового указателя, затем выделить i *sizeof(int) новой памяти для этого нового массива, на который будет указывать указатель.
б) Вы должны создать линеаризованную линейную матрицу, в которой исходный массив будет содержать только числа, а не указатели. На каждой итерации вы должны увеличивать его размер для новых элементов. Линеаризованная треугольная матрица — это одномерный массив чисел, в котором данные сохраняются следующим образом:
ordinary matrix: (/ = wasted memory)
A///
BC//
DEF/
GHIJ
linarized triangular matrix
ABCDEFGHIJ
Вы можете получить доступ к линейному элементу треугольной матрицы E с координатами [y,x] = [2,1] (элемент ‘A’ берется за начало координат), например
sum=0;
for(iy=0;iy<y;iy )
for(ix=0;ix<=y amp;amp; ix<x;ix ) sum ;
//myLinMatr[sum]=='E'