Ошибка сегментации (ядро сброшено), только больший вход

0

Мой код работает отлично, если seive (n) равен 1000000. Если seive (n) больше, чем 10000000, это показывает мне ошибку сегментации (ядро сбрасывается). Я прочитал об ошибке сегментации. Но я не мог с этим справиться.

    #include <stdio.h>
    #include <math.h>

    using namespace std;


    int seive(long int n)
    {
        long int A[n];

        for (long int i = 2; i <= n; i += 1)
        {
            A[i] = i;
        }
        long int root = (int)sqrt(n);

        for(int j = 2; j <= root; j++)
        {

            for(int k = 2*j; k < n ; k = k + j)
            {       
                A[k] = 0;
            }
        }
        int count = 0;
        for (int l = 2; l < n; ++l)
        {
            if(A[l] != 0) count++;
        }
        printf("%d\n", count);

    }

    int main()
    {
        seive( 1000000);
    }
  • 0
    Ваш компилятор, вероятно, размещает VLA в стеке, который предположительно не может обрабатывать 10000000 * sizeof(long int) .
  • 0
    Это может привести к переполнению стека. Если вы используете Linux, введите команду 'ulimit -a' и проверьте размер стека. Я думаю, вы должны использовать malloc вместо массива.
Показать ещё 1 комментарий
Теги:
core
segmentation-fault

3 ответа

3

long int A [n];

Это массив в стеке. Это действительно большой, если N большой. Ваш стек недостаточно велик, чтобы удерживать его в этих случаях, и вы получите ошибку.

Решения включают:

Динамическое выделение памяти: long int * A = (long int *) malloc (n * sizeof (long int));

Динамическое выделение памяти C++ style: long int * A = новый long int [n];

Использование статически выделенного буфера (то есть не в стеке): static long int A [n];

Сделать это глобальным: переместите эту линию на 3 строки.

  • 0
    VLA не может иметь статическую продолжительность хранения, поэтому последние два «решения» - нет . Первый (динамическое распределение) выполним. Помните, n передается в; не фиксированная константа.
  • 0
    и вопрос помечен c ++, поэтому использование malloc не является первым выбором
Показать ещё 3 комментария
2

То, что вы пытаетесь сделать, это попытаться выделить массив с большим количеством элементов в стеке (стек памяти)

long int A[n];

В общем случае вы сможете выделить более крупный массив в куче, используя

int *A = new int[n]
  • 0
    @WhozCraig это ошибка времени выполнения.
2

Ваше автоматическое хранилище облагается за его пределы на вашей платформе по ряду причин.

Во-первых, каждый элемент бесполезен на 63 бита больше, чем нужно, предполагая, что ваша платформа unsigned long int равна 64 бит. Сито обычно должно представлять только одно из двух значений: "true" или "false". Для этого достаточно массива bool с некоторой незначительной настройкой вашего алгоритма.

Во-вторых, хотя первый элемент важен, он не является доминирующим фактором в размере вашего массива. Эта привилегия принадлежит n, верхнему пределу вашего квеста. Ваш запрос на значительное количество места в автоматическом хранилище. Предполагая, что вы обратились к первому и представление bool на вашей платформе - это один байт, флажок-массив из 10000000 записей все равно потребует ок. 9,54 МБ автоматического хранилища, которое не смешно.

Решение представляет собой динамическое хранилище и может быть выполнено несколькими способами, некоторые из которых:

  • Используйте malloc(sizeof(bool)*(n+1)) (обескуражен в современных C++ программах)
  • Используйте new bool[n+1]] (лучше, но все же не очень)
  • Используйте контейнер RAII, такой как std::vector<bool> (теперь мы куда-то получаем)

Ниже показан очень простой пример сита, который использует приведенное выше. Вы можете значительно улучшить это с оптимизированной логикой относительно четных чисел (не нужно даже их хранить) и т.д. Но это не главное. Точка использует динамическое хранилище, желательно что-то с автоматическим временем жизни, которое std::vector<> делает для вас красиво.

#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>

unsigned long int sieve(unsigned long int N)
{
    std::vector<bool> vec(N+1,true);
    unsigned long int res = 1;
    const unsigned long int SR = std::floor(std::sqrtl(static_cast<long double>(N)));

    for (unsigned long int i=2; i<=SR; ++i)
    {
        if (vec[i])
        {
            ++res;
            for (unsigned long int j=(i << 1); j<=N; j+=i)
                vec[j] = false;
        }
    }

    for (unsigned long int i=SR+1; i<=N; ++i)
    {
        if (vec[i])
            ++res;
    }
    return res;
}

int main()
{
    std::cout << sieve(10000000) << '\n';
    return 0;
}

Вывод

664580

который, по моему мнению, верен, если вы не относитесь к тому, что игнорирует 1 (некоторые делают, не знаю почему), и в этом случае это одно.

  • 0
    Простые числа определяются как «делимые ровно на два (разных) числа». 1 нет. Кроме того, наличие 1 в качестве простого числа усложняет некоторые доказательства, но не упрощает их, поэтому для произвольного выбора это логично. Кроме того, не используйте std :: vector <bool>, поскольку он упакован, и будет работать намного медленнее.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню