Ошибка сегментации (ядро сброшено) - эта ошибка отображается только иногда, и я не могу ее исправить - PullRequest
0 голосов
/ 10 ноября 2018

Я видел много разных форумов здесь и в других местах, и я не могу найти, что не так с моим кодом, в частности. У меня нет указателей, так что это может быть что-то только с массивами, которые я использую - я пытался изменить их и посмотреть, что происходит, попытался записать, что происходит и когда, но иногда ошибка появляется иногда. Я только знаю, что это связано с памятью и доступом к тому, чего я не должен, но не могу определить проблему - возможно, больше из них.

#include <stdio.h>
#include <math.h>
typedef int bool;
#define true 1
#define false 0
int main(int argc, char *argv[]){
    int number;
    int test;
    while ((test = scanf("%d", &number)) == 1){
            if (number == 0){
                    return 0;
            }
            if (number < 0){
                    fprintf(stderr, "Error: Chybny vstup!\n");
                    return 100;
            }
            printf("Prvociselny rozklad cisla %d je:\n", number);
            if (number == 1){
                    printf("%d", number);
            }
            else{
                    bool prime[number+1];
                    for(int i = 0; i <= number; i++){
                            prime[i] = true;
                    }

                    for(int j = 2; j * j <= number; j++){
                            if (prime[j] == true){
                                    for (int multiples = 2; prime[j * multiples] <= number; multiples++){
                                            prime[j * multiples] = false;
                                    }
                            }
                    }
                    int result[50];
                    int multipliers[50];
                    for(int i = 0; i <= 50; i++){
                            result[i] = 0;
                    }
                    for(int i = 0; i <= 50; i++){
                            multipliers[i] = 1;
                    }
                    int counter = 0;
                    for (int test=2; test <= number; test++){
                            if (prime[test]){
                                    if (number % test == 0){
                                            number /= test;
                                            result[counter] = test;
                                            counter++;
                                            while(number % test == 0){
                                                    multipliers[counter-1]++;
                                                    number /= test;
                                            }
                                    }
                            }
                    }
                    for (int c = 0; c < counter; c++){
                            if (multipliers[c] > 1){
                                    printf("%d^%d", result[c], multipliers[c]);
                            }
                            if (multipliers[c] == 1){
                                    printf("%d", result[c]);
                            }
                            if (result[c+1] > 1){
                                    printf(" x ");
                            }
                    }
            }
            printf("\n");
    }
    if (test == 0){
            fprintf(stderr, "Error: Chybny vstup!\n");
            return 100;
    }
    }

1 Ответ

0 голосов
/ 11 ноября 2018

Что вы всегда должны делать, это писать свою программу по частям и проверять, работает ли она после завершения каждой функции, прежде чем переходить к новой. Так как вы затем тестируете каждую функцию, которую реализуете отдельно, вы знаете, что любые ошибки наиболее вероятны в функции, которую вы реализовали последней.

В вашем случае эта проблема сразу бросается в глаза:

for (int multiples = 2; prime[j * multiples] <= number; multiples++){
    prime[j * multiples] = false;
}

Здесь вы тестируете prime[j * multiples] <= number, то есть сравниваете флаг с числом. Поскольку поздние флаги обнуляются до конца массива, j*multiples выйдет за пределы массива prime[] и в конечном итоге приведет к аварийному завершению вашей программы.

Тест должен быть, конечно, j * multiples <= number.

Поскольку я работаю по одной функции и одной проблеме за раз, я не знаю, является ли это единственной проблемой, с которой сталкивается твой код. Выяснить это ваша задача. На вашем месте я написал бы кусочно, возможно, при тестировании количество printf() s, чтобы убедиться, что каждая часть работает, чтобы я мог положиться на код, который я уже написал, сосредоточиться на этой части и сделать устойчивый прогресс с минимальным разочарованием.


В последнее время было довольно много вопросов относительно сит Эратосфена. Я всегда считал полезным реализовать абстрактный, динамически размещаемый тип сита и простые функции доступа / модификатора для его изменения. Поскольку в программе должно быть только одно сито, его можно описать с помощью глобальных переменных:

#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>

/* This is the number of bits in an unsigned long.
   The exact value is floor(log(ULONG_MAX + 1)/log(2)),
   but the following definition will be correct on all
   modern architectures: */
#define  ULONG_BITS  (sizeof (unsigned long) * CHAR_BIT)

/* Prime sieve, with a flag for zero and each odd integer,
   one bit per flag. */
static unsigned long  *sieve = NULL;

/* Largest positive integer within the sieve. */
static uint64_t        sieve_max = 4;

/* Number of unsigned longs allocated and initialized in the sieve. */
static size_t          sieve_words = 0;

/* Function to discard the sieve, if no longer needed. */
static inline void  sieve_free(void)
{
    free(sieve);        /* free(NULL); is safe, and does nothing. */
    sieve       = NULL;
    sieve_max   = 4;    /* Since 0, 1, 2, 3, 4 give built-in answers */
    sieve_words = 0;
}

Исходное значение sieve_max равно 4, потому что наша тестовая функция is_prime() обрабатывает 0, 1, 2 и 3 простых числа и все большие четные целые числа в любом случае не простые; это означает, что целые числа от 0 до 4 всегда известны нашим is_prime():

/* Return 1 if number is prime according to sieve,
          0 if known composite/not prime. */
static inline  int is_prime(const uint64_t  number)
{
    /* 0, 1, 2, and 3 are considered prime. */
    if (number <= 3)
        return 1; /* Prime */

    /* All larger even integers are not prime. */
    if (!(number & 1))
        return 0; /* Not prime */

    /* Outside the sieve? */
    if (number > sieve_max) {
        fprintf(stderr, "is_prime(): %" PRIu64 " is outside the sieve!\n", number);
        exit(EXIT_FAILURE);
    }

    {
        const uint64_t       half = number / 2;
        const size_t         w = half / ULONG_BITS;
        const unsigned long  m = 1uL << (half % ULONG_BITS);

        /* The flag for odd number is (number/2)th.
           half / ULONG_BIT  is the word where bit
           half % ULONG_BIT  is in.
           Return 0 if the bit is set, 1 if clear. */
        return !(sieve[w] & m);
    }
}

Мы можем очень легко вырастить сито, установив по умолчанию все новые флаги как "не простые":

static void sieve_upto(const uint64_t  max)
{
    /* Number of words needed for (max+1)/2 bits. */
    const uint64_t nwords = 1 + max / (2 * ULONG_BITS);
    const uint64_t nbytes = nwords * (uint64_t)sizeof (unsigned long);
    const size_t   words = (size_t)nwords;
    const size_t   bytes = words * sizeof (unsigned long);
    unsigned long *temp;

    /* Already covered by the current sieve? */
    if (sieve_max > max)
        return;

    /* We need to be able to handle max+1,
       and neither bytes or words should overflow. */
    if (max >= UINT64_MAX ||
        (uint64_t)words != nwords || (uint64_t)bytes != nbytes) {
        fprintf(stderr, "sieve_upto(): %" PRIu64 " is too high a maximum.\n", max);
        exit(EXIT_FAILURE);
    }

    /* Do we already have all the bytes we need? */
    if (words == sieve_words) {
        sieve_max = max;
        return;
    }

    /* Allocate/reallocate. Note that realloc(NULL, size)
       is equivalent to malloc(size), so this is safe
       even if 'sieve' is NULL. */
    temp = realloc(sieve, bytes);
    if (!temp) {
        fprintf(stderr, "Not enough memory for a sieve up to %" PRIu64 ".\n", max);
        exit(EXIT_FAILURE);
    }
    sieve = temp;

    /* Clear the new words to all zeros. */
    memset(sieve + sieve_words, 0, (words - sieve_words) * sizeof (unsigned long));

    sieve_max   = max;
    sieve_words = words;
}

Наконец, нам нужна функция, которая будет отмечать составное число (не простое):

static inline void not_prime(const uint64_t  number)
{
    /* Primality is internally handled for 0, 1, 2, 3, and 4. */
    if (number <= 4)
        return;

    /* All larger even numbers are internally handled. */
    if (!(number & 1))
        return;

    /* Outside the sieve? */
    if (number > sieve_max) {
        fprintf(stderr, "not_prime(): %" PRIu64 " is outside the sieve!\n", number);
        exit(EXIT_FAILURE);
    }

    {
        const uint64_t       half = number / 2;
        const size_t         w = half / ULONG_BITS;
        const unsigned long  m = 1uL << (half % ULONG_BITS);

        /* Half is the bit index in sieve[].
           half / ULONG_BITS  is the word containing the bit
           half % ULONG_BITS  that needs to be set. */
        sieve[w] |= m;
    }
}

Сито строительства Эратосфена Я оставлю вам; Моя цель - показать, как можно создать и управлять относительно эффективным (то есть сбалансированным использованием памяти и временем выполнения) для нечетных натуральных чисел, используя динамическое управление памятью.

( Проверка того, что простое сито Эратосфена находит все 455 052 511 простых чисел менее 10 000 000 000, занимает менее 90 секунд, и что для всех 323-разрядных простых чисел 203 280 221 требуется менее 30 секунд на моем ноутбуке, используя одно ядро ​​и вышеупомянутые функции. Для более высоких диапазонов лучше использовать оконное сито. Обратите внимание, что функции подсчета простых чисел не учитывают 0 и 1 простые, в отличие от приведенных выше is_prime().)

...