【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.21027

一行を一つのベクトルとするファイルをコマンド行引数で指定しオプションの引数値により出力フォーマットを決めベクトルノルムを返す
投稿者---ひか(2005/05/13 13:40:07)


一行を一つのベクトルとするファイル(各ベクトルはx値とy値が一個以上の空白文字で区切られて並べられている)をコマンド行引数で指定しオプションの引数値により出力フォーマットを決めベクトルノルムを返すというのを作っています。
オプションは
fなら%fフォーマット、f整数なら%.整数fフォーマット、eなら%eフォーマット、e整数なら%.整数eフォーマット
またオプション-f 引数が指定されていなければかわりに環境変数NORM_FORMATを使用。

まずファイルからデータを入力し、ベクトルノルムをどのように計算したらいいかがわかりません。
ベクトルノルム計算でhypot関数を使うことはわかるのですが…。
あと、オプションf整数の部分の整数の数を出力%fに適用するのにどうしたらいいかがわかりません。
オプション-f整数、-e整数は以下のように書いています。
while((ch = getopt(argc,argv, "f:e:")) != -1) {
  switch (ch) {
  case 'f':
    f_number = optarg;
    break;
  case 'e':
    e_number = optarg;
    break;
  default:
    exit(1);
  }
}

上記のソースで-f、-eはどのように宣言したらいいのでしょうか?
助言よろしくお願いします。



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:一行を一つのベクトルとする以下略 21029 επιστημη 2005/05/13 14:28:21


No.21029

Re:一行を一つのベクトルとする以下略
投稿者---επιστημη(2005/05/13 14:28:21)


>上記のソースで-f、-eはどのように宣言したらいいのでしょうか?

何を訊いてるんだかさっぱりわからんです。




この投稿にコメントする

削除パスワード

No.21030

Re:一行を一つのベクトルとする以下略
投稿者---ひか(2005/05/13 14:57:27)


>>上記のソースで-f、-eはどのように宣言したらいいのでしょうか?
>
>何を訊いてるんだかさっぱりわからんです。

オプション-fと-f整数の区別をどうするかなんですが。
-fなら
getopt(argc, argv, "f"))

-f整数なら
getopt(argc, argv, "f:"))

と書きますが、これを同時に
getopt(argc, argv, "ff:"))

とするとswitchの部分以下のようにcase 'f'が2つになり同じものとして判断してしますのでは、と思ったのですが。
while ((ch = getopt(argc, argv, "ff:")) != -1) {
        switch (ch) {
        case 'f':
            f_format = optarg;
            break;
        case 'f':
            f_number = optarg;
            break;
        default:
            exit(1);
        }
    }

    return 0;
}



この投稿にコメントする

削除パスワード

No.21031

Re:一行を一つのベクトルとする以下略
投稿者---まきじ(2005/05/13 15:14:24)


>オプション-fと-f整数の区別をどうするかなんですが。

printf の 書式(第一引数)を、コマンドライン引数からもらう、
ということでしょうか?

-f4 だとしたら printf("%4f"・・・
-e だとしたら printf("%e" ・・・
みたいな

あと、getopt はどういう仕様なのでしょうか?


この投稿にコメントする

削除パスワード

No.21032

Re:一行を一つのベクトルとする以下略
投稿者---REE(2005/05/13 15:14:59)


getoptでは 引数の有無だけが異なるオプションを解析できないようです。

>あと、オプションf整数の部分の整数の数を出力%fに適用するのにどうしたらいいかがわかりません。

printfで、書式の中に変数を含めたい場合は、*を使えます。
詳細は、ご自身で調べてみてください。
また、書式文字をsprintfで作成することも出来ます。



この投稿にコメントする

削除パスワード

No.21041

Re:一行を一つのベクトルとする以下略
投稿者---ひか(2005/05/13 22:55:12)


getoptはコマンド行引数からオプションを取得する関数です。
ただ、REEさんのコメントではこれはこの問題には使えようです。
他に関数を調べてみたのですが、いいのがありません。

出力に関してはまきじさんの言われることで合っています。
printf ("%.*n$f", result);

nはコマンド行引数からもらった第一引数です。
REEさんの言われた通りprintfについて調べ、上のような書き方があるというのがわかったのですがセグメントエラーでした。


この投稿にコメントする

削除パスワード

No.21043

Re:一行を一つのベクトルとする以下略
投稿者---まきじ(2005/05/13 23:20:29)


>printf ("%.*n$f", result);

printf ("%.*f", result); と思いますが?


この投稿にコメントする

削除パスワード

No.21044

Re:一行を一つのベクトルとする以下略
投稿者---ひか(2005/05/13 23:56:15)


>printf ("%.*f", result); と思いますが?

実行したのですが変な動きをしてしまいます。
int n=4;
float re=1.23456;
printf ("%.*f",re);

nにはフォーマットの整数を入れています。
%.4fのようにしたかったのですが。


この投稿にコメントする

削除パスワード

No.21045

Re:一行を一つのベクトルとする以下略
投稿者---まきじ(2005/05/14 00:05:43)


>int n=4;
>float re=1.23456;
>printf ("%.*f",re);
>nにはフォーマットの整数を入れています。
>%.4fのようにしたかったのですが。

printf ("%.*f",n,re); ですね。


この投稿にコメントする

削除パスワード

No.21046

Re:一行を一つのベクトルとする以下略
投稿者---ひか(2005/05/14 01:37:22)


ありがとうございます!
実行できました。

今のところ、出力方法は何とかわかりました。
少しオプションが怪しいのですがオプションに関する関数についてもう少し調べてみます。
ただ、ファイル出力がよくわからなくて中途半端なものしかできませんでした。
ファイルで一行を一つのベクトルとするのでノルムを計算するためにxとyに数字をわけないといけません。
どのようにノルムを計算すればいいでしょうか?
空行でxとyの境を判断しhypot(double x, double y)で計算するのはわかるのですが。


この投稿にコメントする

削除パスワード

No.21051

Re:一行を一つのベクトルとする以下略
投稿者---ぽへぇ(2005/05/14 06:07:17)


fgets で一行読んで, sscanfでxとyに分ける。

>ファイルで一行を一つのベクトルとするのでノルムを計算するためにxとyに数字をわけないといけません。
>どのようにノルムを計算すればいいでしょうか?

>一行を一つのベクトルとするファイル(各ベクトルはx値とy値が一個以上の空白文字で区切られて並べられている)



この投稿にコメントする

削除パスワード

No.21068

Re:一行を一つのベクトルとする以下略
投稿者---ひか(2005/05/15 00:52:36)


皆様回答ありがとうございます。
皆様のヒントを基にためしに書いてみましたが、うまくいきません。
あちこち間違っていると思いますのでご指摘お願いします。
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

static int
number_of_times(const char *s)
{
  long n;
  char *ep;

  errno = 0;
  n = strtol(s, &ep, 10);
  if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE) {
    perror(s);
    exit(1);
  } else if (*ep != '\0' || n < 0 || n > INT_MAX) {
    fprintf(stderr, "%s: illegal number of times\n", s);
    exit(1);
  }
  return (int)n;
}

void Norm(FILE *fp)
{
  char buf[100];
  double x, y;
  double result;

  while(fgets(buf, size buf, fp) != NULL){
    sscanf (buf, "%lf%lf", &x, &y);
    result = hypot(x, y);
  }
  return result;
}

main(int argc,char *argv[])
{
  FILE *fp = NULL;
  int pos;
  const char *f_number;
  const char *e_number;
  char f_form = 0;
  char e_form = 0;
  int ch;
  int c;
  double result;
  int (*filter)(FILE*);
  int retval = 0;

  while ((ch = getopt(argc, argv, "f:e:")) != -1) {
    switch (ch) {
    case 'f':
      f_number = optarg;
      break;
    case 'e':
      e_number = optarg;
      break;
    default:
      exit(1);
    }
  }
  while ((ch = getopt(argc,argv,"fe")) != -1) {
    switch (ch) {
    case 'f':
      f_form = 1;
      break;
    case 'e':
      e_form = 1;
      break;
    default:
      exit(1);
    }
  }

  if (f_number != NULL) {
    int n;
    printf ("%.*f\n", n, NORM);
  }

  if (f_number == NULL) {
    f_number = getenv("NORM_FORMAT");
  }

  if (e_number != NULL) {
    int n;
    printf ("%.*e\n", n, NORM);
  }

  if (f_form){
    if (f_form == NULL){
      f_form = getenv("NORM_FORMAT");
    }
  }

  if (f_form == NULL){
    printf ("%f\n", fp);
  }

  if (e_form){
    printf ("%e\n", NORM);
  }

  if (optind < argc) {
    FILE *fp;
    int pos;

    for (pos = optind; pos < argc; pos ++) {
      if ((fp = fopen(argv[pos], "r")) == NULL) {
        perror(argv[pos]);
        retval = 1;
        continue;
      }
      switch ((*filter)(fp)) {
      case -1:
        perror(argv[pos]);
        retval = 1;
        break;
      case -2:
        perror("(stdout)");
        retval = 1;
        break;
      }
      if (fclose(fp) == EOF) {
        perror(argv[pos]);
        retval = 1;
      }
    }
  } else {
    switch ((*filter)(stdin)) {
    case -1:
      perror("(stdin)");
      retval = 1;
      break;
    case -2:
      perror("(stdout)");
      retval = 1;
      break;
    }
  }
  return retval;
}



この投稿にコメントする

削除パスワード

No.21070

Re:一行を一つのベクトルとする以下略
投稿者---かずま(2005/05/15 07:46:42)


> あちこち間違っていると思いますのでご指摘お願いします。

間違いだらけです。
プログラムを作る上での論理的思考が全くできていないようです。

・初期化していない変数 n や filter の値を使おうとしている。
・未定義の名前 NORM を使おうとしている。
・変数に値を代入したのにそれを使っていない。
・定義した関数を呼び出していない。
・値を返さない関数と宣言しているのに return 文がある。
・f_form = getenv("NORM_FORMAT"); は実行されない。

さて、この問題ですが、getopt を使わないほうがよいのではありませんか?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

const char *progname;

void parse_arg(const char *arg, char *format)
{
    if (arg[1] != 'f' && arg[1] != 'e') {
        fprintf(stderr, "usage: %s  [ -f[n] | -e[n] ]  [ file ]\n", progname);
        exit(1);
    }
    if (arg[2]) 
        sprintf(format, "%%.%d%c\n", atoi(arg+2), arg[1]);
    else
        sprintf(format, "%%%c\n", arg[1]);
}

void norm(FILE *fp, const char *fmt)
{
    char buf[256];  double x, y;

    while (fgets(buf, sizeof buf, fp)) {
        if (sscanf(buf, "%lf%lf", &x, &y) != 2) exit(1);
        printf(fmt, hypot(x, y));
    }
}

int main(int argc, char *argv[])
{
    int index = 1;  char format[16], *p;

    if (p = strrchr(argv[0], '/')) progname = p + 1;
    else if (p = strrchr(argv[0], '\\')) progname = p + 1;
    else progname = argv[0];

    if (argc >= 2 && argv[1][0] == '-') {
        parse_arg(argv[1], format);
        index = 2;
    } else {
        char *env = getenv("NORM_FORMAT");
        if (env) parse_arg(env, format);
        else strcpy(format, "%f\n");
    }
    if (index == argc)
        norm(stdin, format);
    else {
        FILE *fp = fopen(argv[index], "r");
        if (!fp) {
            fprintf(stderr, "%s: can't open %s\n", progname, argv[index]);
            exit(1);
        }
        norm(fp, format);
        fclose(fp);
    }
    return 0;
}



この投稿にコメントする

削除パスワード

No.21071

ありがとうございました。
投稿者---ひか(2005/05/15 13:17:11)


>プログラムを作る上での論理的思考が全くできていないようです。

まだまだ未熟者のため申し訳ありません。

>さて、この問題ですが、getopt を使わないほうがよいのではありませんか?

ご指摘ありがとうございます。
知らない書き方もありとても勉強になりました。

ご指摘していただいた皆様もありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧