otn さんがコメントでも触れていらっしゃいましたが、まずは「エラトステネスのふるい」法を、とりあえず1から100迄で良いので、自分の手で紙に書いて実践し、理解するところから始めることを強くおすすめします。
とは言え、その理解したアルゴリズムを、配列を使った C プログラムに、どのように落とし込めば良いのか、
また、「表示を10の桁ごとに数え、その素数の数だけを’*’で表示」とはどういう意味なのか、
すでに、かなりの時間考えた末、厚い壁にぶち当たった感覚があるのではないかと思います。
(私も昔はそうでしたから)
そこで、昔使っていた C の記憶を掘り起こして(汗)、「自分だったらこうするかな」というサンプルを書き下ろしてみました。
C
1 # include <stdio.h>
2 # include <math.h> /* sqrt() */
3
4 # define MAX_PRIME 1000 /* 素数を調べたい上限 */
5 # define IS_PRIME 0 /* 素数である */
6 # define IS_NOT_PRIME ( ! IS_PRIME ) /* 素数でない */
7
8 int main ( void ) {
9 int primes [ MAX_PRIME ] = { IS_PRIME } ; /* まず配列の全ての要素が「素数である」と仮定する */
10 int sqrt_max_prime = ( int ) sqrt ( ( float ) MAX_PRIME ) ; /* 「エラトステネスのふるい」では全体の平方根より先を調べる必要が無いのでその停止値をあらかじめ求めておく */
11 int step ; /* ふるいにかけた回数(処理の本筋とは関係無いが「エラトステネスのふるい」の収束の速さを可視化するための変数) */
12 int check_prime ; /* ふるいにかける素数 */
13 int i , j ;
14
15 primes [ 0 ] = primes [ 1 ] = IS_NOT_PRIME ; /* 素数の定義により */
16
17 step = 1 ;
18 check_prime = 2 ; /* 最初のふるいは最初の素数を採用する */
19 while ( check_prime < sqrt_max_prime ) {
20 printf ( "step %d, checking prime number = %d\n" , step , check_prime ) ;
21 for ( i = check_prime + check_prime ; i < MAX_PRIME ; i += check_prime ) { /* ふるいの「次」以降は素数ではない */
22 primes [ i ] = IS_NOT_PRIME ;
23 printf ( "%d " , i ) ;
24 }
25 printf ( "\nis not prime\n\n" ) ;
26
27 check_prime += 1 ; /* 次のふるいを仮定する */
28 while ( primes [ check_prime ] == IS_NOT_PRIME ) { /* すでに素数でないものは次のふるいに採用しない */
29 check_prime += 1 ;
30 }
31 step += 1 ;
32 }
33
34 /* 素数を表示 */
35 printf ( "primes is\n" ) ;
36 for ( i = 0 ; i < MAX_PRIME ; i += 1 ) {
37 if ( primes [ i ] == IS_PRIME ) {
38 printf ( "%d " , i ) ;
39 }
40 }
41 printf ( "\n" ) ;
42
43 /* 表示を 10 の桁ごとに調べ、その素数の数だけを '*' で表示 */
44 printf ( "\nhistogram of primes is\n" ) ;
45 for ( i = 0 ; i < MAX_PRIME ; i += 10 ) { /* 10 の桁ごとに処理する */
46 printf ( "%6d : " , i ) ; /* 処理桁を表示 */
47 for ( j = i ; j < i + 10 ; j += 1 ) { /* 10 の桁ごとの中を全て調べる */
48 if ( primes [ j ] == IS_PRIME ) { /* それが素数ならば '*' を表示する */
49 putchar ( '*' ) ;
50 }
51 }
52 printf ( "\n" ) ;
53 }
54
55 return 0 ;
56 }
(11行目の step 変数宣言、20行目、23行目、25行目の printf( )、31行目の step 加算は、「エラトステネスのふるい」法が、いかに収束の早いアルゴリズムであるかを示すためのもので、削除しても動作には問題ありません;ちなみに 4行目の 1000 を 10000 にしても、たいした処理ステップにはなりません)
特に、サンプルの 18行目から 32行目までを、よくご覧下さい。 この部分が、「エラトステネスのふるい」を、私なりに忠実に C で書き表したものです。
紙に1から100までの「領域」と、変数 check_prime の「領域」と、変数 i の「領域」を書いて、
そして変数 sqrt_max_prime の「領域」には、100のルート、つまり 10 を書き込んでおいてから、
「自分がコンピューターになったつもりで」、紙と鉛筆(シャーペン)と消しゴムを使い、このプログラムを「頭と手で」1行ずつ、ていねいに実行してみてください。
まさに「エラトステネスのふるい」の動作そのものだ、という感じがしたと思いますが、いかがでしょうか……。
さて、これで素数は求まりましたが、次の問題である「表示を10の桁ごとに数え、その素数の数だけを’*’で表示」が待っています。
これはサンプルの 44~53行目が相当します。
「10の桁ごとに」というのは、おそらく、00台、10台、20台、30台、40台、50台、60台、70台、80台、90台、100台、110台、……ごとに、という事だと私は解釈しました。 つまりこれは「『10 ごとの素数の個数』の度数分布を表示せよ」ということでしょう。
そうと決まればプログラミングはさほど難しくありません。 10台ごとに処理するループを回して、1ループの中で 0~9 の10個について、それぞれ素数かどうか判定し、素数なら '*' を表示するだけです。
もちろん 10台ごとの改行を忘れてはいけません。
これで度数分布表(ヒストグラム)の完成です。
以上、ご参考になれば幸いです。