C言語関係掲示板

過去ログ

No.979 ファイル内の素数を求める

[戻る] [ホームページ]
No.12766

ファイル内の素数を求める
投稿者---元気(2004/02/14 21:58:41)


C言語初心者の者です。先ず始めに【課題】を記載します。
(環境:Window XP Borland)

あるファイルの中の各行には、複数個の自然数(int型の範囲内)が適当な個数
の空白で区切られている。ファイル内の中の各行について、その行の中にいくつ
素数が入っているかを表示するプログラムを作成せよ!但し、以下の点に注意す
る。
1.その行の中に素数がない場合は0と表示。
2.各行に記されている数値は3桁毎にカンマが入っている。
3.自然数xが素数がどうかを確認する関数primepは与えられているとする
(自分で作る必要なし)。各数値が素数かどうかはこの関数によりチェックする
こと。primepは整数を引数として、その整数が素数であれば1を、そうでなけれ
ば0を返す関数であり、以下のプロトタイプ宣言を持つ。
int primep(int);

【ファイル内の例】
67,888 9,885,386 9,760,492 17 6,516,649
8,977 2,906,996 5,497,281 1,702,305
515,434 7,336,327 8,233,367
これを読み込み各行毎の素数の個数を出力すると
【出力例】
2
0
2
となるようなものです。

このような課題に対して教科書等を参考にして、以下のようなプログラム(授業
で習ったのがこの辺りまでなのでできればこのような感じで解決したい)を作成
しました。しかし、空白処理やカンマ処理等がどうもおかしい?及びコンパイル
時にはエラーが出てしまうなどの問題があります。
C言語の勉強して数ヶ月です。理解していない部分が多数あるかと思いますが、
どなたかご教示願います。

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

  void quit(char *);
  int primep(int);

  int main(int argc, char *argv[])
  {
    FILE *fp;
    char buf[1000],num[100];
    int r,k,n=0;

    if (argc != 2) quit("引数の数が違う");
    if ((fp = fopen(argv[1],"r")) == NULL) quit("ファイルが開けない");
    while (fgets(buf,1000,fp) != NULL) {
      r = 0;
      while (buf[r] != '\n'){
        k = 0;
        for (   ;(buf[r] != ' ') && (buf[r] != '\n'); r++){
          num[k]= buf[r]; k++;
        }
        if (primep(buf));
        num[k] = '\0';
        n += atoi(num);
        for (   ;(buf[r] == ' ') && (buf[r] == ','); r++);
      }
    }
    fclose(fp);
    printf("各行の素数の個数は%d\n",n);
  return 0;
  }

  void quit(char *s)
  {
    puts(s); exit(1);
  }






No.12768

Re:ファイル内の素数を求める
投稿者---おでん(2004/02/14 22:51:49)


処理方法は、いろいろあると思いますが私が考えた場合以下のようになります。

>あるファイルの中の各行には、複数個の自然数(int型の範囲内)が適当な個数
>の空白で区切られている。ファイル内の中の各行について、その行の中にいくつ
>素数が入っているかを表示するプログラムを作成せよ!但し、以下の点に注意す
>る。
>1.その行の中に素数がない場合は0と表示。
>2.各行に記されている数値は3桁毎にカンマが入っている。

・・・と言ってるのですから、数字以外は','と' '(空白)だけ、ということが期待できます。だとすると、空白は置いておいて
まず','を削除してしまったらどうでしょう?

そうすると、最初の行は
67888 9885386 9760492 17 6516649
となりますね。
後は、区切りの空白を頼りに先頭から数字を読み込んで処理を
すればよいのではないでしょうか?


No.12769

Re:ファイル内の素数を求める
投稿者---おでん(2004/02/14 23:34:30)


#include <stdio.h>
#include <stdlib.h>
void quit( char * );
int primep( int );

int main( int argc, char * argv[] ) {
    FILE * fp;
    char buf[1000], num[100];
    int r, k, n = 0;

    if( argc != 2 ) quit( "引数の数が違う" );
    if( ( fp = fopen( argv[1], "r" ) ) == NULL ) quit( "ファイルが開けない" );
    while( fgets( buf, 1000, fp ) != NULL ) {
        r = 0;
        while( buf[r] != '\n' ) {
            k = 0;
            for( ; ( buf[r] != ' ' ) && ( buf[r] != '\n' ); r++ ) {
                num[k] = buf[r]; k++; ←これでは、','もコピーされてしまう。
            }
            if( primep( buf ) ); ←intのはずが文字列を渡している。if文が実行されても意味が無い(';')
            num[k] = '\0';
            n += atoi( num ); ←読み込んだ数字(?)を変換している。素数の個数ではない。
            for( ; ( buf[r] == ' ' ) && ( buf[r] == ',' ); r++ );
        }
    }
    fclose( fp );
    printf( "各行の素数の個数は%d\n", n );
    return 0;
}

void quit( char * s ) {
    puts( s ); exit( 1 );
}

(コンパイル、デバッグしていません (^^;; が)
イメージとしては、こんな感じだと思います。
int PrimeCount( const char * sop )/* sop:読み込んだ行のポインタ    */
{
    int n, cnt ;
    char buf[1000], *dip ;
    dip= buf ;

    while(*sop){ /* 行の終わりまで */
        if( *sop == ',' ){
            /* ','をスキップ */
            sop++ ;
            countinue ;
        }
        /* ','以外をコピー    */
        *dip++ = *sop++ ;
    }
    cnt= 0 ;    /* 素数の数    */
    sop= buf ;  /* ','を削除した行  */
    while(*sop){
        while( isspace(*sop)){
            /* ' 'をスキップ */
            sop++ ;
        }
        n= 0 ;
        while( isdigit(*sop)){
            /* 数字ならintに変換   */
            n *= 10 ;
            n += *sop - '0' ;
            sop++ ;
        }
        if( n != 0 && primep(n)){
            /* 数値が有って、素数ならカウンタを加算   */
            cnt++ ;
        }
    }
    return cnt ;    /* 素数の数を返す  */
}





No.12770

Re:ファイル内の素数を求める(ミス訂正)
投稿者---おでん(2004/02/14 23:37:25)


sop++ ;
countinue ; →continue ;


No.12771

Re:ファイル内の素数を求める
投稿者---あかま(2004/02/15 02:13:10)


こんなんでどうでしょうか。たぶん動く?
#include <stdio.h>
#include <stdlib.h>

void quit(char *s)
{
    puts(s); exit(1);
}
int main(int argc,char *argv[]){
    FILE *fp;
    int i=0,ch,count=0;
    char buf[16];
    if (argc != 2) quit("引数の数が違う");
    if ((fp = fopen(argv[1],"r")) == NULL) quit("ファイルが開けない");
    
    while((ch = getc(fp)) != EOF){
        switch(ch){
            case ',':
                break;
            case ' ':
                buf[i]='\0';
                if(primep(atoi(buf))) count++;
                i=0;
                break;
            case '\n':
                buf[i]='\0';
                if(primep(atoi(buf))) count++;
                printf("%d\n",count);
                i = count = 0;
                break;
            default:
                buf[i] = ch;
                i++;
        }
    }
    return 0;
}


No.12773

Re:ファイル内の素数を求める
投稿者---元気(2004/02/15 14:23:00)


おでんさん、あかまさんありがとうございました。
大変助かりました。ところでもう一つ質問があります。
【課題】では関数primepは与えられており、自分で作る必要はありませんが、
結果を実際に確認するために、あかまさんから頂いたソースに素数判定の
primepを加えました。
しかし、【ファイル内の例】を実行したところ【出力】が次のようになりました。

2
3←ファイル内の2行目には素数はないはず?なのに3とカウントしている
2

これは私のファイル内に問題があるのかそれとも下記ソースに問題があるの
でしょうか?

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

  void quit(char *);
  int primep(int);

  int main(int argc, char *argv[])
  {
    FILE *fp;
    char buf[128];
    int c;
    int i=0,count=0;

    if (argc != 2) quit("引数の数が違う");
    if ((fp = fopen(argv[1],"r")) == NULL) quit("ファイルが開けない");
    while ((c = getc(fp)) != EOF) {
      switch (c){
        case ',':
          break;
        case ' ':
          buf[i] = '\0';
          if (primep(atoi(buf))) count++;
          i = 0;
          break;
        case '\n':
          buf[i] = '\0';
          if (primep(atoi(buf))) count++;
          printf("%d\n",count);
          i = count = 0;
          break;
        default:
          buf[i] = c;
          i++;
      }
    }
    if (fclose(fp) == -1) quit("ファイルが閉じれない");
  return 0;
  }

  void quit(char *s)
  {
    puts(s); exit(1);
  }

  /* こここから下は解答には必要ない */
  int primep(int x)
  {
    int j;

      for ( j=2; j<x; j++ ){
        if ( x%j==0 )return 0; 
        return 1;
      }
  return 0;
  }




No.12774

Re:ファイル内の素数を求める
投稿者---YuO(2004/02/15 14:36:56)


>結果を実際に確認するために、あかまさんから頂いたソースに素数判定の
>primepを加えました。
>しかし、【ファイル内の例】を実行したところ【出力】が次のようになりました。
>2
>3←ファイル内の2行目には素数はないはず?なのに3とカウントしている
>2
>これは私のファイル内に問題があるのかそれとも下記ソースに問題があるの
>でしょうか?

primepの実装が間違っています。
これでは,偶数か奇数かの判定しかできていません。
for文中のreturn 1;を削除して,primepの最後のreturn 0;をreturn 1;にする必要があります。
#1が与えられたときの例外処理も必要。


No.12775

Re:ファイル内の素数を求める
投稿者---元気(2004/02/15 17:25:43)


>primepの実装が間違っています。
>これでは,偶数か奇数かの判定しかできていません。
>for文中のreturn 1;を削除して,primepの最後のreturn 0;をreturn 1;にする必要があります。
>#1が与えられたときの例外処理も必要。

YuOさんレスありがとうございます。
primepのみのソースを以下に書きますが、YuOさんが言っている

>#1が与えられたときの例外処理も必要。

を表すことができません。
どのようにすれば良いのでしょうか?

/* こここから下は解答には必要ない */
  int primep(int x)
  {
    int j;

    for ( j=2; j<x; j++ ){
      if ( x%j==0 ) return 0;
    }
  return 1;
  }





No.12781

Re:ファイル内の素数を求める
投稿者---あかま(2004/02/16 02:06:06)


if(x == 1) return 0;
を関数のアタマにつければok

No.12792

Re:ファイル内の素数を求める
投稿者---元気(2004/02/16 23:16:36)


>if(x == 1) return 0;
>を関数のアタマにつければok

あかまさんありがとうございました。
無事に解決することができました。