掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

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

No.29882

YYYY/MMの判定が解りません
投稿者---初心者(2007/03/07 18:13:39)


MyBirth[MYBIRTH]にYYYY/MMで入力して不正な入力と確定した段階で、生年月日の入力の前に処理を戻し、すべてのチェックにひっかからなかった場合のみ、次のエントリの処理に移れるように、ループで生年月日の処理をさせたいのですがどのように書いてよいか解りません。どなたかご教授願います。


コンパイラ:bcpad
OS:XP Home edition




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

#define MAXNAME 11  /* 名前の最大入力文字数*/
#define MYBIRTH 8  /* 生年月日の年の形*/
#define MAXCASE 10 /* 最大ユーザー件数 */

void get_string(char *p_str, int xMaxChar); 

struct user
{
    char Name[MAXNAME]; 
    char MyBirth[MYBIRTH]; 
};

void main()
{
    struct user s_user[MAXCASE]; 
    int i, j = 0; 


    while( j < MAXCASE ){/* データ入力 */
    
        printf("名前:"); 
        get_string(s_user[j].Name, MAXNAME);
        
        
        if ( s_user[j].Name[0] == '0' ) {/* 1文字目が'0'のとき */
            break;
        }
        
        
        if ( s_user[j].Name[0] == '\0' ) {/* 改行のみのとき */
            printf("再入力\n");
            continue;
        }
        
       
        printf("生年月日");
        get_string(s_user[j].MyBirth, MYBIRTH);
        for (i = 0; i < 4; i++) {/* 最初の4行が 各桁の文字が0〜9以外のときエラー */
            if( s_user[j].MyBirth[i] < '0' || '9' < s_user[j].MyBirth[i] ){
                printf("年の入力形式が正しくありません\n");
                 
            }
        }
        

        printf("累計件数 = %d件\n\n", ++j); 
    }
       
       
       
       
        printf("累計件数 = %d件\n\n", ++j); 
    }
    
    printf("入力データ表示\n"); 
    
    
    
    for (i = 0; i < j; i++){
        printf("%d件目\n", i + 1); 
        printf("名前 = %s\n", s_user[i].Name); 
        printf("生年月日 = %s\n", s_user[i].MyBirth); 
    }


void get_string(char *p_str, int xMaxChar)
{
    int i = 0; 
    int CH; 
    
    while ( (CH = getchar()) != EOF && CH != '\n' ){
        if ( i < xMaxChar - 1 ) {
            *p_str = CH; 
            p_str++; 
            i++; 
        }
    }
    *p_str = '\0'; 
}



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:YYYY/MMの判定が解りません 29884 kolona 2007/03/07 19:22:54


No.29884

Re:YYYY/MMの判定が解りません
投稿者---kolona(2007/03/07 19:22:54)


>MyBirth[MYBIRTH]にYYYY/MMで入力して不正な入力と確定した段階で、生年月日の入力の前に処理を戻し、すべてのチェックにひっかからなかった場合のみ、次のエントリの処理に移れるように、ループで生年月日の処理をさせたいのですがどのように書いてよいか解りません。どなたかご教授願います。

コンパイルが通らないですね。括弧の対応付けがおかしくなっています。
分からないのは入力された値のチェックですか?
それとも再入力を促す方法ですか?

入力された値のチェックなら
s_user[j].MyBirth
の文字列を別のchar配列にコピーしてatoiで変換する方法がありますが。
どういう年代を不正とするのか分からないので何とも言えません。
全桁が数字として認識できれば良いのであれば今の記述で良いと思います。
まあ、isdigit(int c);なんて関数もあるので自分で書かなくても良いのですが。

再入力を促す方法だったら、不正入力の際にはjをインクリメントしない、もしくはデクリメントしておいて
printf("累計件数 = %d件\n\n", ++j);
でインクリメントさせるのが楽だと思います。



この投稿にコメントする

削除パスワード

No.29886

Re:YYYY/MMの判定が解りません
投稿者---初心者(2007/03/07 20:02:00)


kolona様、返信ありがとうございます。


>入力された値のチェックなら
>s_user[j].MyBirth
>全桁が数字として認識できれば良いのであれば今の記述で良いと思います。

入力されたのが7文字か判定して、それから最初の4文字が数字で5文字目がスラッシュで6、7文字目で1〜12の数字である。っというようにチェックしたいのです。

そのどれかでも当てはまらないものがあれば再入力を促すというようにしたいのです。

この場合はどうすればよいのでしょうか。



この投稿にコメントする

削除パスワード

No.29889

Re:YYYY/MMの判定が解りません
投稿者---yoh2(2007/03/07 22:19:16)


まずは入力された文字列の判定方法について。

>入力されたのが7文字か判定して、それから最初の4文字が数字で5文字目がスラッシュで6、7文字目で1〜12の数字である。っというようにチェックしたいのです。

そのチェックしたい項目そのまま並べるとよいです。正しくない項目が見付かったら、
その場で再入力を促すようにすればよいでしょう。(その方法は後述)

a) 最初の4つが数字かどうかはisdigit()でチェックできます。
b) 5文字目がスラッシュかどうかは、そのまま'/'との比較すればよいでしょう。
c) 最後の、1〜12の数字というのは、strtol()を使うというのも手ですが、どうせ2文字しかないので、
c-1) 6〜7文字目が数字であることをチェック。
c-2) (6文字目 - '0') * 10 + (7文字目 - '0')が1〜12の範囲にあることをチェック。
とした方がお手軽かもしれません。(*)
d) 最後に8文字目が'\0'であることをチェック。

(*) strtol()は、先頭の空白を読み飛ばしてしまうので、それを不正な形式としたいなら、
6文字目が数字であることをチェックする必要が出てきます。
そうすると、他に見るべき文字が1文字(8文字目を勘定に入れても2文字)しかないのに、
わざわざstrtol()を使うのは少し大袈裟な気がします。
ちなみに、入門書などでは、10進文字列->整数の変換関数として、atoi()しか紹介されていない場合も
ありますが、atoi()は入力が正しくない場合の結果が不定ですから、入力の正当性チェック
には向いていません。


次に、再入力を行う方法について。

>そのどれかでも当てはまらないものがあれば再入力を促すというようにしたいのです。
>
>この場合はどうすればよいのでしょうか。

生年月日の形式が正しくなければ名前から入力し直ししてよいなら、kolonaさんの
方法(jの値を細工する)かcontinueすれば再入力できますね。
生年月日のみを再入力させたいなら、生年月日入力部分とチェック部分を無限ループで囲み、
正しい形式ならばループを脱出する、といった方法を取ることによって実現できます。
    for(;;){
        printf("生年月日");
        get_string(s_user[j].MyBirth, MYBIRTH);

        前述のチェックaで不正と判断されたらcontinue;
        ...
        前述のチェックdで不正と判断されたらcontinue;

        break; /* すべてのチェックをクリアした場合のみここにくる */
    }

ちなみに、チェック部分を関数化すれば、do-whileを使って、少しすっきりした形にできます。
    do{
        printf("生年月日");
        get_string(s_user[j].MyBirth, BYBIRTH);
    }while(!is_valid_birthday(s_user[j].MyBirth);
    /* ↑ is_valid_birthday()はチェック関数。 */


以下余談。

実用化するなら、入力の妥当性チェックとは別に、そもそも正しく読み込めたかどうかの
チェックと、読み込みに失敗した場合の対策を加えるべきです。そうでなければ、途中で
EOFに達したりエラーが起こったりすると、再入力のループが延々と繰り返されてしまいます。

get_string()と同様のことを実現する関数fgets()が標準ライブラリにあります。
名前が似ているgets()という関数はよく使用厳禁だと言われますが、それはバッファ長が
指定できないことによる危険性によるもので、バッファ長の指定ができるfgets()はむしろ
積極的に使っていきたい関数です。
前述の、読み込み成功のチェックも同時にできますのでお得です。


この投稿にコメントする

削除パスワード

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