товарищи программисты.
В общем, нужно с помощью calloс создать одномерный массив, затем заполнить его рандомными числами, а после добавить в начало этого массива введенное с клавиатуры кол-во чисел Фибоначчи. Я написал код, но при больших значениях программа вылетает, в чём ошибка и что вы вообще посоветуете подкорректировать?
И оцените сам код, дайте максимально конструктивную критику : что я использую не так, что вообще не нужно использовать...
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void FillArray(int *array,int size);
void OutArray(int *array,int size);
int Fib(int amount);
int main()
{
srand(time(NULL));
int size = 0, amount = 0;
int* first = 0;
cout << "Enter size : ";
cin >> size;
first = (int*) calloc(size, sizeof(int));
FillArray(first, size);
OutArray(first, size);
cout << "How many Fib's number do you want to add : ";
cin >> amount;
int n_s = amount + size;
// size = 3, n_s = 7;
first = (int*) realloc(first,n_s * sizeof(int));
if(first == NULL){
cout << "Memory is not available!" << endl;
free(first);
}
for(int a = n_s, i = 0, j = size; i <= size; i++, j--, a--){
*(first + a)=*(first+j);
*(first+j) = 0;
}
for(int i = 0; i < amount; i++){
*(first+i) = Fib(i);
}
OutArray(first, n_s);
int count = 0;
free(first);
first = NULL;
}
void FillArray(int *array,int size){
for(int i = 0; i < size; i++){
*(array + i ) = rand() % 100;
}
}
void OutArray(int *array,int size){
for(int i = 0; i < size; i++){
cout << *(array + i) << " ";
}
cout << endl;
}
int Fib(int amount){
if(amount == 0)
return 0;
if(amount == 1)
return 1;
else
return Fib(amount - 1 ) + Fib(amount - 2);
}
Если закрыть глаза на разные ошибки, то программа скорее всего вылетает из-за рекурсивного вычисления чисел Фибоначчи. Да, для объяснения рекурсии она хороша, но для реальной жизни - нет.
Поэтому напишем ее по другому (я постарался сохранить стиль Вашего кода).
void FillFib(int *array, int size)
{
if (size > 0) *(array) = 1;
if (size > 1) *(array+1) = 1;
for (int i = 2; i < size; i++) {
*(array+i) = *(array+i-1) + *(array+i-2);
}
}
если нужно хотя бы один элемент - заполним его единицей. Если хотя бы два - то их оба. А дальше - по классике - сумма двух предыдущих.
и в коде main вместо цикле вызываем
FillFib(first, amount);
Теперь даже при больших числах "летает".
Но потом я обратил внимание на странный код "перемещения" данных.
for(int a = n_s, i = 0, j = size; i <= size; i++, j--, a--){
*(first + a)=*(first+j);
*(first+j) = 0;
}
и вот оно. При самом первом обращении происходит копирования элемента за пределы массива. *(first+a)
=> *(first+n_s)
. Перепишем
for(int a = n_s-1, j = size-1; j>=0; j--, a--){
*(first + a)=*(first+j);
}
и зануление я убрал. Но в целом я бы тут на memove заменил бы (и так пишем в си стиле).
И посмотрим ещё на этот участок
first = (int*) realloc(first,n_s * sizeof(int));
if(first == NULL){
cout << "Memory is not available!" << endl;
free(first);
}
вначале типичная ошибка использования realloc. Если ему не удалось выделить память, то он возвратит NULL, но исходную память не тронет. И в этом случае Вы ее потеряете. И если даже так, то вызывать free для заведомо NULL указателя не имеет смысла - он ничего не сделает. Для учебного примера думаю этот if можно убрать, просто не забыв выше добавить проверки на то, что пользователь запросил нулевой размер (или, что хуже, отрицательный).
И в этом же куске вторая ошибка. Допустим, что память не выделилась. Но код продолжается. А указатель то уже NULL...
Хорошо бы его так переписать
int* temp = (int*) realloc(first,n_s * sizeof(int));
if(temp == NULL){
cout << "Memory is not available!" << endl;
free(first);
return 1;
}
first = temp;
По поводу отсутствия return в конце main - стандарт позволяет это делать. Это легально.
1) У вас метка C++ - тут лучше использовать RAII, а не указатели (их уже лет 15 не используют в явном виде, это же не С) для работы с массивами данных есть множество контейнеров (std::vector и т.д.);
1.1) В С++ есть new и delete, использовать С аллокаторы - не оч...
1.2) В С++ есть nullptr для указателей а не интовый NULL;
2) Генерация "случайных чисел" - тут лучше взять не rand() + time, а ПДСЧ по типу std::mt19937_64, а лучше /dev/random и /dev/urandom в Linux или рандом из CryptoAPI в Win32;
3) Между оператором и скобкой ставится проел (не if(..), а if (..)) к for это тоже относится;
4) using namespace std - на взгляд многих людей - моветон, всегда можно обратиться к этому namespace через std::..
5) Для приведения типов в C++ есть касты https://www.tutorialspoint.com/cplusplus/cpp_casting_operators.htm , надо использовать их, а не С_стайл_каст((int*)ptr);
6) В Вашей функции int Fib(int amount) else вообще лишний, перед финальным return else не пишется;
7) У вас плавает codestyle, в main { с новой строки, а тут void FillArray(int *array,int size) прилипла и нет пробела между аргами функции.
8) У вас определено int main(), но она ничего не возвращает, нужно хотя бы return exitcode;
Вот пример Вашей задачи в мое видении..
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <limits>
#include <cstdint>
std::vector<uint64_t> RandomUintDataArray(const std::size_t size, const std::size_t low_bound,
const std::size_t hight_bound) noexcept {
static std::random_device r_device{};
static std::mt19937_64 entropy_generator{r_device()};
static std::uniform_int_distribution<> ranc_distribution(low_bound, hight_bound);
static auto PRNG{std::bind(ranc_distribution, entropy_generator)};
std::vector<uint64_t> random_data;
try {
random_data.resize(size);
std::generate(std::begin(random_data), std::end(random_data), PRNG);
} catch (std::bad_alloc& exc) {
std::cerr << exc.what() << std::endl;
random_data.clear();
random_data.shrink_to_fit();
}
return random_data;
}
uint64_t FibonacciValueOfIndex(std::size_t n) noexcept {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
uint64_t v_curr{1}, v_priv{0};
while (n-- > 1) {
v_curr += v_priv;
v_priv = v_curr - v_priv;
}
return v_curr;
}
int main() {
constexpr uint64_t data_size{40};
auto data{RandomUintDataArray(data_size, 0, 100)};
if (!data.size()) {
return -1;
}
std::cout << "Data before insert : " << std::endl;
std::copy(std::begin(data), std::end(data), std::ostream_iterator<uint64_t>{std::cout, "; "});
std::cout << std::endl;
uint64_t n_for_fib{20};
if (n_for_fib > data.size()) {
return -2;
}
for (auto i{0}; i < n_for_fib; ++i) {
data.at(i) = FibonacciValueOfIndex(i);
}
std::cout << "Data after insert : " << std::endl;
std::copy(std::begin(data), std::end(data), std::ostream_iterator<uint64_t>{std::cout, "; "});
std::cout << std::endl;
return 0;
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Пытаюсь разобраться в многопоточности и mutexПо задумке сначала должен выполниться thread Calc(Stream), после его окончания должен выполниться thread...
Код C++, Visual Studio 2019, urlmon подключен, вызываю так: