• 締切済み

プログラミング(構造体、ファイル入出力、コマンドライン引数)

プログラミング(C言語)の質問です。 コマンドライン引数を使って3点の座標の並びが1レコードに記録されたファイルを読み込み、3点の並びが、時計回りに三角形を形作るか、反時計回りに三角形を形作るか、直線(あるいは一点)上にあるかを判定し、読み込んだ各レコードを判定に従って、3つの出力ファイル(時計回りだけのファイル、反時計回りだけのファイル、直線だけのファイル)に分配して書き込むプログラムを作成しています。しかし、なかなか完成しない上、どこが間違っているのかも分かりません。下に私が作ったプログラムを添付しておくのでどこが間違っているのか指摘してください。よろしくお願いします。 #include <stdio.h> #define BUFLEN 1024 int main(int argc, char *argv[]){ int difference_x1, difference_y1, difference_x2, difference_y2; int cross_product; char buf[BUFLEN]; struct points{ int x; int y; } point_a, point_b, point_c; FILE *fp1, *fp2; while(fgets(buf, BUFLEN, fp1) != NULL){ fp1 = fopen(argv[1], "r"); fgets(buf, BUFLEN, fp1); sscanf(buf, "%d,%d,%d,%d,%d,%d", &point_a.x, &point_a.y, &point_b.x, &point_b.y, &point_c.x, &point_c.y); difference_x1 = point_b.x - point_a.x; difference_y1 = point_b.y - point_a.y; difference_x2 = point_c.x - point_a.x; difference_y2 = point_c.y - point_a.y; cross_product = difference_x1 * difference_y2 - difference_x2 * difference_y1; if(cross_product < 0){ fp2 = fopen("clockwise.txt", "w"); }else if(cross_product > 0){ fp2 = fopen("counterclockwise.txt", "w"); }else if(cross_product == 0){ fp2 = fopen("straightline.txt", "w"); } fprintf(fp2, "%d,%d,%d,%d,%d,%d", point_a.x, point_a.y, point_b.x, point_b.y, point_c.x, point_c.y); fclose(fp2); } fclose(fp1); return 0; }

みんなの回答

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.5

>どこが間違っているのか指摘してください。 1)  >while(fgets(buf, BUFLEN, fp1) != NULL){  ↑コンパイル時に「警告」がでますよね、fp1 は値が代入される前に使われたと。   これを無視せず、  >fp1 = fopen(argv[1], "r"); を前にし、fp1 を確定しましょう。 2)   >fp2 = fopen("clockwise.txt", "w");   これらファイルオープン3行は「新規」ですので、「書き込み」の条件合致の都度、新たにオープンします。   (= >最後に判定したものしか書き込まれていません) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 以上、大きく2点について修正したものでアドバイス(BorlandC++5.5.1)。  あと、  ・fgets() + sscanf() を fscanf() で代用しています。  ・出力3ファイルのファイルポインタを使っています。  http://www.bohyoh.com/CandCPP/C/Library/fscanf.html 《蛇足》 プログラムの作成・実行は、自己責任?の世界です。 不具合時に、困るのは自分です。   例)実行時、コマンドラインに、入力ファイル名を付け忘れた場合。 これへの対応をコード化しておくも、しないも自由です。 ただし、 ☆課題等でソースを提出する場合は、上への対応や「ファイルがオープンできない」場合等の「エラー処理」を記述しておくことが必須となります。 #include <stdio.h> #define TOKEI 0 #define HNTKI 1 #define SLINE 2 int main( int argc, char *argv[] ) {  int difference_x1, difference_y1, difference_x2, difference_y2;  int cross_product;  FILE *fp1, *fp2, *fP[ 3 ];  struct points{   int x;   int y;  }point_a, point_b, point_c;  fp1 = fopen( argv[ 1 ], "r" );  fP[ TOKEI ] = fopen( "clockwise.txt", "w" );  fP[ HNTKI ] = fopen( "counterclockwise.txt", "w" );  fP[ SLINE ] = fopen( "straightline.txt", "w" );  while( 6 == fscanf( fp1, "%d,%d,%d,%d,%d,%d", &point_a.x, &point_a.y, &point_b.x, &point_b.y, &point_c.x, &point_c.y ) ){   difference_x1 = point_b.x - point_a.x;   difference_y1 = point_b.y - point_a.y;   difference_x2 = point_c.x - point_a.x;   difference_y2 = point_c.y - point_a.y;   cross_product = difference_x1 * difference_y2 - difference_x2 * difference_y1;   fp2 = fP[ SLINE ];   if( cross_product < 0 ) fp2 = fP[ TOKEI ];   if( cross_product > 0 ) fp2 = fP[ HNTKI ];   fprintf( fp2, "%d,%d,%d,%d,%d,%d\n", point_a.x, point_a.y, point_b.x, point_b.y, point_c.x, point_c.y );  }  fcloseall();  return( 0 ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.4

まあ、あれでしょうか。 fp2を3種類のファイルで使い回す代わりに、 1ファイルについて1ファイルポインターを対応させるのが、 わかりやすくてよいかもしれません。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.3

>3つのファイルができたのはいいんですが、最後に判定したものしか書き込まれていません。 だとすると、 >指摘された通り直したら上手くいきました。 そうではなくて、まだうまくいきません、ですね。 書込み用ファイルのオープンモードはどうなっていますか?

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.2

>while(fgets(buf, BUFLEN, fp1) != NULL){ この「前に」ファイルをオープンしてください。 >fp1 = fopen(argv[1], "r"); この文は、ループの外に出してください。そして、 この文の前で、コマンドライン引数の個数をチェックしてください。 また、オープンがうまくいかなかったときの処理を加えてください。 >fgets(buf, BUFLEN, fp1); この文は不要です。 >fp2 = fopen("clockwise.txt", "w"); 毎回、新規作成モード("w")でよいのでしょうか? また、オープンがうまくいかなかったときの処理を加えてください。 >}else if(cross_product == 0){ 負でも正でもなければゼロに決まっていますので、 if~ は冗長です。else { でじゅうぶんです。 まだ、他にあるかもしれません。

bluesky445
質問者

補足

回答ありがとうございます。 指摘された通り直したら上手くいきました。 ただ、3つのファイルができたのはいいんですが、最後に判定したものしか書き込まれていません。判定したもの全てが書き込まれているようにしたいのですがどうしたらよいでしょうか?

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

「何が間違いなのか」はわからなくても「実行結果がどう自分の期待通りでないのか」はわかりますよね? まずはそれを提示してください。

関連するQ&A

  • c言語  2つのファイルを行ごとに読み込むプログラミング

    c言語  2つのファイルを行ごとに読み込むプログラミング 0.txt と 1.txt という2つのテキストフォルダがあり 0.txt の中身は a a b b 1.txt の中身は c c d d というものとします。 これら2つのフォルダを読み込むとき まず1つのフォルダの1行目(a a)を表示し 他方の1行目(c c) 2行目(d d)を表示させて 続いて1つのフォルダの2行目(b b)を表示し 他方の1行目(c c) 2行目(d d)を表示させたいのです。 つまり実行結果が a a c c a a d d b b  ←理想の実行結果です c c b b d d となるようにしたいのですが #include <stdio.h> #include <stdlib.h> #define STR_MAX 256 int main(void) { FILE *fp, *fp2; int i, j, k; char buf[STR_MAX]; char buf2[STR_MAX]; fp = fopen("0.txt", "r"); fp2 = fopen("1.txt", "r"); if (fp == NULL && fp2 == NULL){ printf("\n"); } while(fgets(buf, STR_MAX, fp) != NULL){ while(fgets(buf2, STR_MAX, fp2) != NULL){ printf("%s%s", buf,buf2); } printf("\n"); } fclose(fp); fclose(fp2); return 0; } このプログラミングの実行結果は a a c c a a d d となり、0.txtの2行目(b b)は表示されません。 おそらく while 文 を2重にすることで 不具合が起きているのだと思うのですが 色々と調べた結果、これ以外に プログラミングが思いつきません。 私の理想の実行結果にするためには どこを訂正させると良いのでしょうか? 恐れ入りますが ご回答 どうかよろしくお願いいたします。

  • 【C言語】コマンドライン引数の標準入出力

    【C言語】コマンドライン引数の標準入出力 コマンドライン引数で、ファイル名を3つ渡します。-aの次のコマンドライン引数が、出力ファイル名です。 <<例>> ・実行モジュール -a 出力ファイル名 -b ファイル名 -c ファイル名 ・実行モジュール -c ファイル名 -a 出力ファイル名 -b ファイル名 もし出力ファイルが指定されなかった場合に、標準入出力を使いたいのですが、どうしたらいいかわかりません。 下記がソースの一部です。これをどう改造したらよいでしょうか。 分かる方いらっしゃいましたらご回答いただけると幸いです。 宜しくお願いします。 //出力ファイルを取得、書き込みモードでオープン for(j=1;j<argc-1;j++){ if(strcmp(argv[j],"-o")==0){ if((fo = fopen(argv[j+1],"w"))==NULL){ printf("open error!!\n"); exit(1); } } } while(fgets(buf,sizeof(buf),fp)!= NULL){ if(strstr(buf,"keyword")!= NULL){ //出力ファイルに出力 fprintf(fo,"%d:%s",line,buf); } }

  • 構造体でのファイル操作

    1 2 3 1 2 3 1 2 3 1 2 3 みたいに書き込まれた txtデータを構造体でよみこみたいのですけどうまくいきません プログラムはこんなかんじです int i=0; FILE *fp; fp = fopen("Data.txt","r"); while (fscanf(fp, "%d,%d,%d",a.no[i],a.A[i],a.B[i] ) != EOF){ i++; } fclose(fp); a.noが1列目で a.Aが2列目で a.Bが3列目です Debug assertion failed  と表示されます どうしてでしょうか?

  • 構造体の要素すべてに対する四則演算の方法を教えてください.

    構造体の要素すべてに対する四則演算の方法を教えてください. たとえば、 2点a,bの座標成分x,y,zをそれぞれの座標ごとに足す方法を教えてください. 下のようにx,y,z成分を持ったa,bがあります。 struct point{ int x; int y; int z; }; struct point a; struct point b; struct point c; この場合, c=a+b; と書くことができず, それぞれの成分ごとに以下のように足さなくてはなりません. c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; この方法でできるのですが, 非常に効率的でないのでなにかもっと簡単に記述する方法を教えてください. お願いいたします.

  • ファイル入出力について教えて下さい。

    ご覧いただきありがとうございます。 数値を入力して、数値を出力する方法を教えて頂きたいです。 ・   ・   ・ fp = fopen( "a.txt", "a" ); for( i = 16383; i >= 0; i-- ) { fprintf( fp, "%d", i ); } fclose( fp ); ・   ・   ・ data = (int *)malloc(32768); fp = fopen( "a.txt", "r" ); for( i = 0, i <= 16383; i++ ) { fscanf( fp, "%d", data+i ); } fclose( fp ); ・   ・ ・ 以上の記述で、入力はうまくいくのですが、出力の際に数値でなくなってしまいます。どうしてでしょうか? ご存じの方がおりましたら、ご回答よろしくお願いいたします。

  • 「コマンドライン引数チェック」て何

    #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; char gyou[1024]; int gyousuu = 0; if ( argc < 2 ){ printf("file mei ga nai\n"); return -1; } fp = fopen(argv[1], "r"); if ( fp == NULL ){ printf("fopen dekinai\n"); return -2; } while(fgets(gyou, sizeof(gyou), fp) != NULL){ gyousuu++; } fclose(fp); printf("gyousuu=%d\n", gyousuu); return 0; }    以上のプログラムはご覧のとおり、「ファイルの行数を計算」のプログラムです。 さて以上の  if ( argc < 2 ){ printf("file mei ga nai\n"); return -1; } は「コマンドライン引数チェック」を行っています。・・・  if ( argc < 2 ){の「argcは2以上である必要がある」と参考書に書いてあります。   以上ですが意味が日光手前ですが、プログラムの行数をカウントするうえで、  「コマンドライン引数チェック」とはどんな作業を行っているとこなのでしょうか!?  よろしくお願いします。  

  • コマンドライン入力

    以下のプログラムはまず、  1  a.datファイルを作る。  2  コマンドラインから、a.datを指定。    指定場所の文字を読み取るコードです。    何度やっても、意味不明な記号などがでます。    どこがおかしいか    教えてください。   /**************** a.datファイルの作成 ***********/ /***************** プログラム **************/ int main(void) {  char a[ ]= "abcde";    FILE *fp;    fp=fopen("a.dat","wb");    fwrite(a,sizeof(a),1,fp); return 0; } /*************** コマンドラインから指定 **************/ /*************** 指定の場所を書き出す ****************/ int main( int argc,char *argv[ ] ) {    long a;    FILE *fp;    fp=fopen("argv[1]","rb");      printf("バイト数入力\n");      scanf("%ld",&a);    fseek(fp,a,SEEK_SET);    printf("%c\n",fgetc(fp)); return 0; }

  • コマンドライン引数

    すいません、java初心者です。 コマンドライン引数として渡されたファイルを16進表示したいのですが、右のテキスト部分の文字のあいうえおなどの日本語部分が出てきこず途中で止まってしまいます・・・ 何が悪いか、改善方法教えてください!! 宜しくお願い致します!!!! import java.io.*; class Lesson1{ static char ch[]= {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; //16種類 static int c1,c2; public static void main(String args[]) { System.out.println("Address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF"); System.out.println("--------+--------------------------------------------------+------------------"); if(args.length !=1){ System.out.println("ファイル名を指定してください。"); //ファイルがついてない場合。 System.exit(1); } try { //入力ストリームを作成。 FileInputStream fis= new FileInputStream(args[0]); //ファイル読み取り //InputStreamReader in = new InputStreamReader(fis, "SJIS"); BufferedReader br= new BufferedReader(new FileReader(args[0])); // 読込みループ。 int d=0; int c; // 読み込んだものをsに入力。 String str; int n = 0, k = 16; //0~Fまでの数字 String s=""; while( (c = in.read()) != -1) { if( k > 15 ) { System.out.println(" "+s); //右のパーツ s = ""; System.out.printf("%08X: ",n); //Address k = 0; } d++; //バイト数表示 n++; k++; // 整数cを上位4ビットc1、下位4ビットc2に分解。 c1 =c/16; c2 =c%16; System.out.print(" " + ch[c1] + ch[c2]); //真ん中のパーツ。 //System.out.printf(" "+Integer.toHexString(c)); if( (c<= 0x00 || c<= 0x19) ) { //右のパーツ(表示できない場合 s = "."; } else{ //表示できる場合 s =s+(char)c; } } //String s1=String.valueOf(c); //int len =s.length(); System.out.println(""); System.out.println(""); System.out.println("ファイルサイズは"+d+"byteでした。"); // 入力ストリームを閉じる。 in.close(); } catch ( IOException e ) { System.out.println("ファイルの読み込みに失敗しました。"); //ファイル名が正しくない場合。 } } } 実行結果 Address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF --------+--------------------------------------------------+------------------ 00000000: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcdef 00000010: 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 ghijklmnopqrstuv 00000020: 77 78 79 7A 41 42 43 44 45 46 47 48 49 4A 4B 4C wxyzABCDEFGHIJKL 00000030: 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5AException in thread "main" j ava.lang.ArrayIndexOutOfBoundsException: 772 at Lesson1.main(Lesson1.java:55)

    • ベストアンサー
    • Java
  • プログラミング 構造体に関する質問です

    4人を個別で平均点を求めるプログラミングを作りたいのですが外部関数にする方法がいまいちわかりません。あとこのプログラムもなぜかエラーがでてしまいます。どなたかご教授お願いします #include<stdio.h> typedef struct{ char name[4]; int point[4]; }tokutenn; int main(void) { int x, y; int sum[5] = {0}; double ave[5] = {0.0}; tokutenn sd[5] = {{"kou", {55, 44, 33,34}}, {"mei", {34, 74, 67,56}}, {"sai", {72, 36, 68,35}}, {"kai",{34, 82, 73,56}}, for(x = 0; x < 4; x++){ for(y = 0; y < 3; y++){ sum[x] += sd[x].point[y]; } } for(y = 0; y < 4; y++){ ave[y] = sum[y] / 3.0; } for(y = 0; y < 4; y++){ printf( "%sの平均は%.10f点\n",&sd[y].name[0], ave[y]); } return 0; }

  • ファイル入出力について教えて下さい。2

    ご覧いただきありがとうございます。 何度も低レベルな質問で申し訳ありません。 A.PRMというファイルに、 I have a pen. He has a pen. と2行の文章が入っています。 これを読み取り、printfで画面表示させたいのですが、 #include <stdio.h> int main(void) { FILE *fp; char a[50]; char b[50]; if( (fp=fopen("A.PRM", "r" )) != EOF ) { fgets( a, 49, fp ); fgets( b, 49, fp ); } fclose( fp ); printf( "a = %s\n", a ); printf( "b = %s\n", b ); return 0; } とすると、fgetsで余分な改行が入ってしまいます。 fgetsの代わりにfscanfを使用すると、今度はスペースの前までしか読み込んでくれず、「a = I」「b = He」と表示されてしまいます。 どうしたらよいでしょうか? 是非ご回答いただきたいです。よろしくお願いいたします。