←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


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

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

 詳しくはこちら



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

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


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

No.3735

入力時にデータをチェックしたい
投稿者---momo(2005/05/08 17:29:46)


scanf関数などで値を読み込んだ後、読み込んだ値の大きさをチェックするということをしたいのですが、どのようにすれば良いでしょうか?
具体的には、キーボードから入力された数値データが、unsiged intで表現できる最大値(UINT_MAX)より大きければ、もう一度入力しなおさせ、最終的に、正当な値をunsigned int の変数に代入したいと思っています。
fgets だと桁単位でしか判定できないので困っています。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:入力時にデータをチェックしたい 3736 RAPT 2005/05/08 18:52:27
<子記事> Re:入力時にデータをチェックしたい 3737 shu 2005/05/08 21:33:05
<子記事> Re:入力時にデータをチェックしたい 3748 nop 2005/05/09 10:39:01


No.3736

Re:入力時にデータをチェックしたい
投稿者---RAPT(2005/05/08 18:52:27)


scanf()だけではかなり厳しい。
fgets()で行単位で読み込んで、sscanf()で解析できます。
sscanf()の戻り値の意味とかをヘルプで調べると吉。

環境依存では、_kbhit()と_getch()の組み合わせで解決する場合も
あることにはあるが、やっぱり環境依存。



この投稿にコメントする

削除パスワード

No.3738

入力時にデータをチェックしたい
投稿者---momo(2005/05/08 22:10:05)


レス有難うございます。

sscanfの戻り値について調べてみましたが、「変換が一つも行われないまま入力誤りが発生すると、マクロEOFの値を返す。それ以外の場合、代入された入力項目の個数を返す。この個数は、入力中に照合誤りが発生すると、変換指定子に対応する実引数の数よりも小さくなることもあり、0になることもある。」とあり、次のようなコードを書いてためしてみました。
int main( void )
{
    char      buf[30];
    unsigned  x;
    int       scan_count;
    
    printf( "x = " );
    
    fgets( buf, sizeof(buf), stdin );
    scan_count = sscanf( buf, "%u",&x );

    printf( "scan_count = %d\n", scan_count );
    printf( "x = %u\n", x );

    return 0;
}

実行してみると、

bash-2.05b$ ./test2
x = 1234567890123456
scan_count = 1
x = 4294967295

xの値は unsigned int の最大値になります。
scan_countの値も1になっており、変換にも成功してしまっているようです。
ここからどう判定したら良いのでしょうか?


この投稿にコメントする

削除パスワード

No.3740

入力時にデータをチェックしたい
投稿者---momo(2005/05/08 22:20:44)


最初に環境を記述せずすみませんでした。
環境は、Linux(32bit)、kernel2.6.10、gcc3.3.5 です。
よろしくお願いします。


この投稿にコメントする

削除パスワード

No.3744

Re:入力時にデータをチェックしたい
投稿者---Blue(2005/05/08 23:27:13)


入力として有効なのは数値のみであることが前提として(英字や全角数値、空白文字はダメ)

  1. fgetsで標準入力から文字列として取得 (文字数はUINT_MAXの桁数+改行文字数+終端文字数)
  2. fgetsで取得した文字列の中に改行文字が存在しない場合は桁数オーバということで、 バッファをクリアし再入力させる。
  3. fgetsで取得した文字列が全て数値であるかチェックする。 (ただし末尾の改行文字は含めない。) 数値以外の文字がある場合は再入力させる。
  4. 文字列としてUINT_MAXの文字列と比較し、それ以下なら数値に変換する。 それ以上の場合は再入力させる。
てな考え方はどうでしょうか?



この投稿にコメントする

削除パスワード

No.3746

Re:入力時にデータをチェックしたい
投稿者---Blue(2005/05/09 00:17:28)


>fgetsで標準入力から文字列として取得
>(文字数はUINT_MAXの桁数+改行文字数+終端文字数)

ってよく考えてみたら、
000 ・・・・ 0001 の入力もダメになりますね、、、
(これを許さないにした場合は数字チェックのときに先頭の0はNGという判定が必要)

やはり、入力された文字を全て取得してから、先頭の0をトリムして
という処理が必要ですね。

# 行の文字列をすべて取得するのがめんどいかも。



この投稿にコメントする

削除パスワード

No.3737

Re:入力時にデータをチェックしたい
投稿者---shu(2005/05/08 21:33:05)


unsigned longの変数を用意する。
scanf()で代入。
(UINT_MAX)と比較。

……ちなみにunsigned intは、unsignedと省略表記ができます。


この投稿にコメントする

削除パスワード

No.3739

入力時にデータをチェックしたい
投稿者---momo(2005/05/08 22:18:45)


レス有難うございます。

unsigned int と unsigned long int のビット数が同じ処理系ですので、その手は使えませんでした。
最初に環境を記述せずにすみませんでした。
環境は、Linux(32bit)、kernel2.6.10、gcc3.3.5 です。


この投稿にコメントする

削除パスワード

No.3747

Re:入力時にデータをチェックしたい
投稿者---おでん(2005/05/09 10:32:11)


>レス有難うございます。
>
>unsigned int と unsigned long int のビット数が同じ処理系ですので、その手は使えませんでした。
>最初に環境を記述せずにすみませんでした。
>環境は、Linux(32bit)、kernel2.6.10、gcc3.3.5 です。

1.前後の空白を削除
2.数字かどうかを判定
3.数字でない場合エラー
4.先頭の'0'を削除
5.桁数が9桁以下か判定
6.9桁以下の場合、そのままscanf()にて変換
7.11桁以上の場合、unsigned int/unsigned longで表現できないためエラー
8.10桁の場合、unsigned int/unsigned longで表現可能か判定する。
→文字列で見るか数値で見るか?
 →数値の場合は、文字列を適当に区切って個別に変換
 e.g. "1234567890" -> 12345 67890
9.表現可能な場合、そのままscanf()にて変換
10.表現不可の場合、unsigned int/unsigned longで表現できないためエラー

ですかね?


この投稿にコメントする

削除パスワード

No.3750

入力時にデータをチェックしたい
投稿者---momo(2005/05/09 23:03:12)


皆様、沢山のレス有難うございます。
勝手ですが、ここでお礼を言わせていただきます。

報告ですが、
8.10桁の場合、unsigned int/unsigned longで表現可能か判定する。
以外は動作するようになりました。
もう少しがんばってみます。


この投稿にコメントする

削除パスワード

No.3751

Re:入力時にデータをチェックしたい
投稿者---かずま(2005/05/10 03:00:47)


参考になりますか?
#include <stdio.h>
#include <ctype.h>
#include <limits.h>

int get_uint(unsigned int *u)
{
    char buf[1024];  unsigned int x, y;
    unsigned char *p = (unsigned char *)buf;

    if (!fgets(buf, sizeof buf, stdin)) return 0;
    while (isspace(*p)) p++;
    if (!isdigit(*p)) return 0;
    for (x = *p - '0'; isdigit(*++p); ) {
        if (x > UINT_MAX/10) return 0;
        y = x * 10;  x = y + (*p - '0');
        if (x < y) return 0;
    }
    *u = x;
    return 1;
}

int main(void)
{
    unsigned int u;
    
    while (printf("> "), !get_uint(&u)) ;
    printf("%u\n", u);
    return 0;
}



この投稿にコメントする

削除パスワード

No.3752

入力時にデータをチェックしたい
投稿者---momo(2005/05/10 06:29:37)


レス有難うございます。

大変参考になりました。
私が書いたコードよりかなりすっきりしていて、わかりやすかったです。
http://www.pro.or.jp/~fuji/mybooks/cdiag/cdiag.1.6.html
ここのページの、「 初心者のプログラムを見てつくづく思うのは、しなくても良いコーディングが実に多いことです。1行で済むところを5行も10行もかけたり、」というところが、身にしみました。
お蔭様でとても良い勉強になりました。

改めてこの場をかりてお礼をさせていただきます。
有難うございました。


この投稿にコメントする

削除パスワード

No.3749

Re:入力時にデータをチェックしたい
投稿者---NykR(2005/05/09 10:40:38)


>unsigned int と unsigned long int のビット数が同じ処理系ですので、その手は使えませんでした。
>最初に環境を記述せずにすみませんでした。
>環境は、Linux(32bit)、kernel2.6.10、gcc3.3.5 です。

ならば unsigned long long intですね。
# long long intでもこの場合は多分大丈夫


この投稿にコメントする

削除パスワード

No.3748

Re:入力時にデータをチェックしたい
投稿者---nop(2005/05/09 10:39:01)


strtol() を使用するのはどうでしょうか?

【以下 MSDN より抜粋】
  strtol 関数は、変換によってオーバーフローが発生しない限り、文字列 nptr に示されている値を返します。
  オーバーフローが発生すると LONG_MAX または LONG_MIN を返します。
  変換できなかった場合は 0 を返します。
  オーバーフローまたはアンダーフローが発生すると、グローバル変数 errno に ERANGE を設定します。


この投稿にコメントする

削除パスワード

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




掲示板提供:Real Integrity