#include #include #include #define MAXSTR 10 /* 名前の長さ */ #define MAXENT 10 /* 件数 */ typedef struct { char *name_ptr; long year; long month; long day; } CARD; int getdec(int keta, int* ans); int con_gets2(char *str, int buf_size); void keyflush(int input); int usort3(CARD **card, int entry); int cmpstr3(CARD **str1, CARD **str2); int chgstr3(CARD **str1, CARD **str2); /* ----- 滅入ん ----- */ void main() { int i; int entry = 0; int dec; char tmp[MAXSTR + 1]; char *p; CARD *card[MAXENT]; char eday [] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* ダミー, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 */ printf("%d 文字以内で氏名を入力してください (%d件)\n", MAXSTR, MAXENT); for (i = 0; i < MAXENT; i++) { printf("名前入力 %d :", i + 1); if (con_gets2(tmp, MAXSTR + 1) == EOF) { /* 名前の入力を受け付ける */ break; } p = malloc(sizeof(CARD)); if (p == NULL) { /* 確保できないらしいし */ printf("メモリを確保できません!\n"); return; } *(card + i) = (CARD *)p; p = malloc(strlen(tmp) + 1); /* メモリ確保 */ if (p == NULL) { /* 確保できないらしいし */ printf("メモリを確保できません!\n"); return; } (*(card + i))->name_ptr = p; /* 確保したメモリのポインタを配列に保存 */ strcpy((*(card + i))->name_ptr, tmp); /* 確保したメモリに文字列を複写 */ do { /* 年入力 */ printf(" 年入力 %d :", i + 1); if (getdec(4, &dec) != -1) { /* 数字以外が入力されてる? */ if (dec >= 1) { /* 紀元前とかはナシにしようや */ (*(card + i))->year = dec; break; /* 入力成功 */ } } printf("Error! : 正しい年を入力して下さい\n"); } while (1); do { printf(" 月入力 %d :", i + 1); if (getdec(4, &dec) != -1) { /* 数字以外が入力されてる? */ if (dec >= 1 && dec <= 12) { /* 1 〜 12 の間かね? */ (*(card + i))->month = dec; break; /* 入力成功 */ } } printf("Error! : 正しい月を入力して下さい\n"); } while (1); do { printf(" 日入力 %d :", i + 1); if (getdec(4, &dec) != -1) { if (dec >= 1 && dec <= eday[(*(card + i))->month]) { /* 月別の末日も考慮してみた */ (*(card + i))->day = dec; break; /* 入力成功 */ } } printf("Error! : 正しい日を入力して下さい\n"); } while (1); printf("累計件数:%d 件\n", ++entry); } printf("----------\n"); if (usort3(card, entry) == NULL) { /* メモリブロックを指すポインタを入れ替える */ printf("メモリ不足らしい\n"); } for (i = 0; i < entry; i++) { /* 並び替えた内容を表示する */ printf("%-10s %4d年 %2d月 %2d日\n", (*(card + i))->name_ptr, (*(card + i))->year, (*(card + i))->month, (*(card + i))->day ); } for (i = 0; i < entry; i++) { free((*(card + i))->name_ptr); free(*(card + i)); } } /* ----- 関数の定義 ----- */ int getdec(int keta, int* ans) { int input; /* 1 文字入力の値 */ int sign = 2; /* 最初のループ時:2 整数:0 負数:1 */ int i = 0; /* 繰り返しカウンタ ※ 1 文字読み込んだら増やす */ *ans = 0; /* 文字→数値変換の結果を初期化 */ while ((input = getchar()) != '\n') { i++; /* 繰り返しカウンタを増やす */ if (sign == 2) { /* 符号判定 ※最初の 1 回のみ実行される */ if (input == '-') { /* 負数の時 */ sign = 1; /* 負数フラグ On */ input = getchar(); /* '-' を読み飛ばす */ i++; /* 繰り返しカウンタを増やす */ } else { sign = 0; /* 負数フラグ Off */ } } if (i > keta) { /* 繰り返しの判定 */ break; /* 所定回数に達したら抜ける */ } if (input >= '0' && input <= '9') { *ans = (*ans * 10) + (input - '0'); /* 文字数字を 10 進数に変換 */ } else { keyflush(input); return -1; /* 数字以外の入力ならエラー (-1) */ } } if (sign == 2) { /* 改行だけの入力はエラー */ keyflush(input); return -1; } if (sign) { *ans *= -1; /* 負数の時はそんな感じで */ } keyflush(input); return 0; } /* ---- キーボードから文字列を入力 ---- */ /* 行頭で '0' が入力されると EOF を返す */ /* それ以外は 1 を返す */ int con_gets2(char *str, int buf_size) { int cnt = 0; int flag = 1; char ch; while ((ch = getchar()) != '\n') { /* '\n' が出現するまで繰り返し */ if (flag && ch == '0') { /* 行頭で '0' が入力された場合 */ keyflush(ch); return EOF; } else { flag = 0; } if (cnt < buf_size - 1) { /* 改行待ちなんでバッファクリアは考慮していない */ *(str + cnt) = ch; cnt = cnt + 1; } } *(str + cnt) = '\0'; return 1; } void keyflush(int input) { while (input != '\n') { /* 入力バッファのクリア簡易版 */ input = getchar(); } } /* 概要:配列を並べ替える関数 2 (Buble sort) */ /* 引数:char** str 配列のポインタのポインタ, int entry 配列の要素数 */ /* 返値:成功 = 1 (必ず成功する) */ int usort3(CARD **card, int entry) { int i; char tmp; while (entry > 1) { i = 0; while (i < entry - 1) { /* 件数 - 1 回のループ */ if (cmpstr3(card + i, card + i + 1) == 1) { /* それぞれのメモリブロックの比較 */ if (chgstr3(card + i, card + i + 1) == NULL) { /* A が大きい時にポインタを入れ替える */ return NULL; /* 今回の処理ではエラー発生しないけどお約束でw */ } } i++; /* 桁数をインクリメント */ } entry--; /* 件数をデクリメント */ } return 1; } /* 概要:配列を比較する関数 2 (2 つの配列ブロックの比較) */ /* 引数:char** str1 配列のポインタのポインタ 1, char** str1 配列のポインタのポインタ 2 */ /* 返値:A > B の時 = 1, A == B の時 = 0, A < B の時 = -1 */ int cmpstr3(CARD **str1, CARD **str2) { int i; char *a; char *b; a = (*str1)->name_ptr; b = (*str2)->name_ptr; for (i = 0; ;i++) { /* カウンタを進めつつ無限ループ */ if (*(a + i) > *(b + i)) { /* A が大きい */ return 1; } else if (*(a + i) < *(b + i)) { /* B が大きい */ return -1; } if (*(a + i) == '\0' || *(b + i) == '\0') { /* 文字列の終端に達した */ break; } } return 0; /* ここにくるのは同じ文字列なのなのだ */ } /* 概要:配列を入れ替える関数 2 (2 つの配列ブロックの入れ替え) */ /* 引数:char** str1 配列のポインタのポインタ 1, char** str1 配列のポインタのポインタ 2 */ /* 返値:成功 = 1 (必ず成功する) */ int chgstr3(CARD **str1, CARD **str2) { CARD *p; /* ポインタのポインタってのでポインタを入れ替え */ p = *str1; /* バッファに A を退避 */ *str1 = *str2; /* 以下月並み (-_-;) */ *str2 = p; return 1; }