Решето Эратосфена — реализация на языке C

Я что-то упускаю, но не могу найти что. Мне также дали файл input2.c, и в нем есть функция print_prim, которую мне не разрешено изменять.

Для n=10 всегда печатается

4, 5, 7, 9, 

Я знаю, что в функции print_prim есть i+2, но я не могу решить эту проблему. Опять же, мне не разрешено изменять функцию print_prim. Кто-нибудь может увидеть, что мне не хватает?


main.c


#include <stdio.h>
#include <stdlib.h> 
#include "input2.h"

int main() {
    int n = lese_int();
    int laenge = n-1; 
    int *array;  
    array = malloc(sizeof(int) * laenge);  
    for (int i = 2; i <= n; i++) {
        array[i] = 1;  
    }

    for(int i=0;i<=n;i++) {
        if(array[i] == 1){
            for(int j = i ; i*j <= n ; j++){
                array[i*j] = 0;
            }   
        } 
    }
    print_prim(array, laenge);
    free(array); 
    return 0;
}

функция print_prim

void print_prim(int *array, int laenge) {
    for (int i=0; i<laenge; i++) {
        if (array[i] == 1) {
            printf("%d, ", i+2);
        }
    }
    printf("\n");
}

person keser    schedule 24.10.2018    source источник
comment
Не могли бы вы отформатировать код?   -  person Paul Ogilvie    schedule 24.10.2018
comment
Вы выделяете malloc(sizeof(int) * (n-1)), но ваш цикл выполняется, пока i <= n. Вы пишете 2 элемента слишком много.   -  person Holger    schedule 24.10.2018
comment
Всегда ли i*j <= n будет меньше leange?   -  person Paul Ogilvie    schedule 24.10.2018
comment
Из функции print_prim видно, что записи сдвинуты на 2. Это означает, что число 2 находится в индексе 0. for (int i = 2; i <= n; i++) {array[i] = 1;} Это должно быть array[i-2] одинаковым для всех обращений к array.   -  person Gerhardh    schedule 24.10.2018
comment
привет @Holger, в каком цикле слишком много элементов? какой-то конкретный или все?   -  person keser    schedule 24.10.2018
comment
@Gerhardh, извините, нет, когда я это делаю, единственный выход - 2,   -  person keser    schedule 24.10.2018
comment
Пожалуйста, задайте вопрос. Нет вопроса, на который нужно ответить.   -  person José Manuel Ramos    schedule 24.10.2018


Ответы (2)


Все, что вам нужно, это обычное сито, сдвинутое на 2 элемента.

int main() {
  int n;
  scanf("%d", &n);

  int *a = (int*)malloc(sizeof(int) * (n - 1));
  for (int i = 0; i < n - 1; i++ ) a[i] = 1;

  for (int i = 2; i*i <= n; i++) {
    if (a[i-2] == 1) {
      for (int j = i * i; j <= n; j+=i ) a[j-2] = 0;
    }
  }

  print_prim(a, n - 1);

  free(a);
  return 0;
}

Объяснение:

  • Выделите n-1 элементов для представления чисел от 2 до n включительно.
  • Инициализируйте все элементы с помощью 1. Почему? Потому что, глядя на print_prim, он печатает значения, равные 1. Итак, все наши простые числа нужно сдвинуть на 2, и его значение должно быть 1.
  • Начиная с 2, мы помечаем все кратные простым числам как 0. Те, которые остаются 1, являются простыми числами. Подробнее см. https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.
  • Поскольку print_prim смещается на 2, нам нужно передать n-1 в качестве второго аргумента для включительной печати.
person Mukul Gupta    schedule 24.10.2018
comment
Спасибо, Мукул, очень приятно. Не могли бы вы объяснить свой подход? Я думаю, что они немного разные. - person keser; 24.10.2018
comment
Встроенные форсы трудно расширить. Если вы хотите добавить больше строк в этот код, вам понадобятся фигурные скобки, но начинающий программист этого не заметит. - person José Manuel Ramos; 24.10.2018
comment
@aomerk, код смещается на два элемента только для того, чтобы функция print_prim работала должным образом. - person José Manuel Ramos; 24.10.2018
comment
@JoséManuelRamos Я не думаю, что ты так полезен, как ты думаешь. Пожалуйста, помогите людям, кроме меня. - person keser; 24.10.2018
comment
@MukulGupta извините, но часть, которую я не мог понять, заключалась в том, что я зацикливался до j * i и так далее. Ваша математика немного отличается. я * я , j = я + я и j + = я - person keser; 24.10.2018
comment
@aomerk Математика такая же. Вместо умножения я использовал сложение. В вашем случае вы должны были сделать i*j - 2, поскольку вы используете значения j из i. Фактически, в моем случае мы могли бы также начать с i*i во внутреннем цикле. Я отредактирую его, потому что он более оптимален. - person Mukul Gupta; 24.10.2018

Переформатирование кода

Обычный шаг, чтобы помочь вам, — отформатировать для нас

#include <stdio.h>
#include <stdlib.h> 
#include "input2.h"

int main ( void )
{
  int n = lese_int();
  int laenge = n - 1; 
  int *array;

  array = malloc( sizeof( int ) * laenge );

  for ( int i = 2; i <= n; i++ )
  {
    array[i] = 1;
  }

  for ( int i = 0; i <= n; i++ )
  {
    if ( array[i] == 1 )
    {
      for ( int j = i; i * j <= n; j++ )
      {
        array[ i * j ] = 0;
      }
    }
  }

  for ( int i = 0; i < laenge; i++ )
  {
    printf( "%d, ", array[i] );
  }

  printf( "\n" );
  print_prim( array, laenge );
  free( array );
  return ( 0 );
}

И функция print_prim:

void print_prim ( int *array, int laenge )
{
  for ( int i = 0; i < laenge; i++ )
  {
    if ( array[i] == 1 )
    {
      printf( "%d, ", i + 2 );
    }
  }
  printf( "\n" );
}

Примечание: этот стиль является личным, и он не предназначен для создания религиозных пламенных войн с использованием пробелов, как у меня, или скручивания фигурных скобок вниз.


При чтении обнаружены ошибки:

Вы используете C99. Примите это во внимание, прежде чем что-то менять. (знаю свой язык)

Вы делаете выделение памяти из n - 1 элементов, но пытаетесь получить доступ от элемента 2 к элементу n, включая оба, в первом for цикле. (узнать, как работает выделение памяти)

Массивы начинаются с нуля (вставить шутку), поэтому вы не можете добраться ни до элемента n, ни до элемента n - 1.

print_prim печатает только значение плюс 2 элемента массива, содержащего 1. Другими словами: попробуйте найти все позиции в массиве, который содержит 1, и увеличьте эту позицию на 2. (знать, как читать-отладка< /эм>)


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

person José Manuel Ramos    schedule 24.10.2018
comment
Я не уверен, что это отвечает на вопрос. :/ - person gsamaras; 24.10.2018
comment
Во всяком случае, нет никаких вопросов. - person José Manuel Ramos; 24.10.2018