#include <stdio.h> #include <stdlib.h> #include <string.h> //#define MEMBER_NO 1 /* 番号を表す定数値 */ #define PHYSCHECK_VISION 1 /* 視力を表す定数値 */ #define PHYSCHECK_HEIGHT 2 /* 身長を表す定数値 */ #define PHYSCHECK_NAME 4 /* 氏名を表す定数値 */ #define String_Max 4 /*--- 身体データ型 ---*/ typedef struct{ double vision; /* 視力 */ int height; /* 身長 */ } Body ; /*--- 身体検査データ型 ---*/ typedef struct{ Body body; /* 身体データ型 ---*/ char *name; /* 氏名 */ } PhysCheck ; /*--- ノード ---*/ typedef struct __node { PhysCheck data; /* データ */ struct __node *next; /* 後続ポインタ*/ } Node; /*--- 線形リスト ---*/ typedef struct { Node *head; /* 先頭ノードへのポインタ */ Node *crnt; /* 着目ノードへのポインタ */ } List; /*--- 会員の氏名の比較関数 ---*/ int MemberNameCmp(const PhysCheck *x, const PhysCheck *y){ return strcmp(x->name, y->name); } int MemberVisionCmp(const PhysCheck *x, const PhysCheck *y){ return x->body.vision < y->body.vision ? -1 : x->body.vision > y->body.vision ? 1 : 0; } int MemberHeightCmp(const PhysCheck *x, const PhysCheck *y){ return x->body.height < y->body.height ? -1 : x->body.height > y->body.height ? 1 : 0; } /*--- 会員データ(番号と氏名)の表示(改行なし)---*/ void PrintMember(const PhysCheck *x){ printf("視力:%.2lf 身長:%d 名前:%s\n", x->body.vision, x->body.height, x->name); } /*--- 会員データ(番号と氏名)の表示(改行あり)---*/ void PrintLnMember(const PhysCheck *x){ printf("視力:%.2lf 身長:%d 名前:%s\n", x->body.vision, x->body.height, x->name); } /*--- 会員データ(番号と氏名)の読込み ---*/ PhysCheck ScanMember(const char *message, int sw){//scanf()で入力後にmain(void)のswitch文からここに来る PhysCheck temp,over; // x = ScanMember("末尾に挿入", MEMBER_NO | MEMBER_NAME) char x[String_Max]; printf("%s するデータを入力してください。\n", message); if (sw & PHYSCHECK_NAME) { do{ printf("氏名:"); scanf("%s", x); if(strlen(x) <= String_Max) break; printf("入力できる文字数は%d文字です。\n", String_Max); }while(1); temp.name = calloc(1,sizeof(char)); strcpy(temp.name , x); } if(sw & PHYSCHECK_VISION){ printf("視力:");scanf("%lf",&(temp.body.vision)); } if(sw & PHYSCHECK_HEIGHT){ printf("身長:");scanf("%d",&(temp.body.height)); } return temp; } /*--- 一つのノードを動的に生成 ---*/ static Node *AllocNode(void){ return calloc(1, sizeof(Node)); } /*--- n の指すノードの各メンバーに値を設定 ----*/ static void SetNode(Node *n, const PhysCheck *x, const Node *next){// InsertRearの場合,SetNode(ptr->next, x, NULL); n->data = *x; // データ xはtemp.noとtemp.nameの情報を保持 n->next = next; // 後続ポインタ (ptr->next)->nextをNULLにする } /*--- 線形リストを初期化 ---*/ void Initialize(List *list){ list->head = NULL; /* 先頭ノード */ list->crnt = NULL; /* 着目ノード */ } /*--- 関数 compare によって x と一致すると判定されるノードを探索 ---*/ Node *Search(List *list, const PhysCheck *x, int compare(const PhysCheck *x, const PhysCheck *y)){ Node *ptr = list->head;//if (Search(&list, &x, MemberNameCmp) != NULL) while (ptr != NULL) { if (compare(&ptr->data, x) == 0) { /* キー値が一致 */ list->crnt = ptr; return ptr; /* 探索成功 */ } ptr = ptr->next; /* 後続ノードに着目 */ } return NULL; /* 探索失敗 */ } /*--- 先頭にノードを挿入 ---*/ void InsertFront(List *list, const PhysCheck *x){ Node *ptr = list->head; list->head = list->crnt = AllocNode(); SetNode(list->head, x, ptr); } /*--- 末尾にノードを挿入 ---*/ void InsertRear(List *list, const PhysCheck *x){//xはtemp.noとtemp.nameの情報を保持 if (list->head == NULL) // 空であれば。 List struct内の情報が (*)だからList *listとする InsertFront(list, x); /* 先頭に挿入 */ else { Node *ptr = list->head; while (ptr->next != NULL){ ptr = ptr->next;// □ □ NULL だったら左辺のptrがNULLの前の □ を指したときwhile1文終了 } ptr->next = list->crnt = AllocNode();//AllocNode: return calloc(1, sizeof(Node)); SetNode(ptr->next, x, NULL);//static void SetNode(Node *n, const Member *x, const Node *next)。上にある }//後続ポインタをNULLにして末尾ノードがいかなるノードも指さないようにする }//SetNode( ↑ ) /*--- 先頭ノードを削除 ---*/ void RemoveFront(List *list){ PhysCheck temp; if (list->head != NULL) { Node *ptr = list->head->next; /* 2番目のノードへのポインタ */ free(list->head); /* 先頭ノードを解放 */ // free(temp.name); list->head = list->crnt = ptr; /* 新しい先頭ノード */ } } /*--- 末尾ノードを削除 ---*/ void RemoveRear(List *list){ if (list->head != NULL) { if ((list->head)->next == NULL) /* ノードが一つだけであれば */ RemoveFront(list); /* 先頭ノードを削除 */ else { Node *ptr = list->head; Node *pre; while (ptr->next != NULL) { pre = ptr; ptr = ptr->next; } pre->next = NULL; /* pre は末尾から 2 番目 */ free(ptr); /* ptr は末尾 */ list->crnt = pre; } } } /*--- 着目ノードを削除 ---*/ void RemoveCurrent(List *list){ if (list->head != NULL) { if (list->crnt == list->head) /* 先頭ノードに着目していれば */ RemoveFront(list); /* 先頭ノードを削除 */ else { Node *ptr = list->head; while (ptr->next != list->crnt) ptr = ptr->next; ptr->next = list->crnt->next; free(list->crnt); list->crnt = ptr; } } } /*--- 全ノードを削除 ---*/ void Clear(List *list){ while (list->head != NULL) /* 空になるまで */ RemoveFront(list); /* 先頭ノードを削除 */ list->crnt = NULL; } /*--- 着目ノードのデータを表示 ---*/ void PrintCurrent(const List *list){ if (list->crnt == NULL) printf("着目ノードはありません。"); else PrintMember(&list->crnt->data); } /*--- 着目ノードのデータを表示(改行付き)---*/ void PrintLnCurrent(const List *list){ PrintCurrent(list); putchar('\n'); } /*--- 全ノードのデータをリスト順に表示 ---*/ void Print(const List *list){ if (list->head == NULL) puts("ノードがありません。"); else { Node *ptr = list->head; puts("【一覧表】"); while (ptr != NULL) { PrintLnMember(&ptr->data); ptr = ptr->next; /* 後続ノードに着目 */ } } } /*--- 線形リストの後始末 ---*/ void Terminate(List *list){ PhysCheck temp; Clear(list); /* 全ノードを削除 */ free(temp.name); } /*--- メニュー ---*/ typedef enum { TERMINATE, INS_FRONT, INS_REAR, RMV_FRONT, RMV_REAR, PRINT_CRNT, RMV_CRNT, SRCH_VISION, SRCH_HEIGHT, SRCH_NAME, PRINT_ALL, CLEAR } Menu; /*--- メニュー選択 ---*/ Menu SelectMenu(void){ int i, ch; char *mstring[] = { "先頭にノードを挿入", "末尾にノードを挿入", "先頭のノードを削除", "末尾のノードを削除", "着目ノードを表示", "着目ノードを削除", "視力で検索", "身長で検索", "氏名で探索", "全ノードを表示", "全ノードを削除" }; do { //do-while文 for (i = TERMINATE; i < CLEAR; i++) {//enumの0番目 printf("(%2d) %-18.18s ", i + 1, mstring[i]);//mstring[i]==*(mstring + i) if ((i % 3) == 2) putchar('\n'); } printf("( 0) 終了 :"); scanf("%d", &ch);//enumの何番目かを選択,ex)2を入力したら"末尾にノードを挿入"=INS_REAR } while (ch < TERMINATE || ch > CLEAR);//enumの要素数外を指定したらもう一度ex)-1,13,など return (Menu)ch;//main(void)に戻ってswich文で各動作に移る } /*--- メイン ---*/ int main(void){ Menu menu; List list; PhysCheck x; Initialize(&list); /* 線形リストの初期化 */ do { switch (menu = SelectMenu()) { case INS_FRONT : /* 先頭にノードを挿入 */ x = ScanMember("先頭に挿入", PHYSCHECK_NAME | PHYSCHECK_VISION | PHYSCHECK_HEIGHT); InsertFront(&list, &x); break; case INS_REAR : /* 末尾にノードを挿入 scanf()で2を入力した場合*/ x = ScanMember("末尾に挿入", PHYSCHECK_NAME | PHYSCHECK_VISION | PHYSCHECK_HEIGHT);//Member ScanMember(const char *message, int sw){ //temp(temp.noとtemp.name)が返され、xに代入される InsertRear(&list, &x);// |演算子:両方0のときのみ0。それ以外は1にする演算子 break; case RMV_FRONT : /* 先頭ノードを削除 */ RemoveFront(&list); break; case RMV_REAR : /* 末尾ノードを削除 */ RemoveRear(&list); break; case PRINT_CRNT : /* 着目ノードのデータを表示 */ PrintLnCurrent(&list); break; case RMV_CRNT : /* 着目ノードを削除 */ RemoveCurrent(&list); break; case SRCH_VISION : /* 視力による探索 */ x = ScanMember("探索",PHYSCHECK_VISION); if (Search(&list, &x, MemberVisionCmp) != NULL) PrintLnCurrent(&list); else puts("その視力のデータはありません。"); break; case SRCH_NAME : /* 氏名による探索 */ x = ScanMember("探索", PHYSCHECK_NAME); if (Search(&list, &x, MemberNameCmp) != NULL) PrintLnCurrent(&list); else puts("その名前のデータはありません。"); break; case SRCH_HEIGHT://身長による探索 x = ScanMember("探索",PHYSCHECK_HEIGHT); if (Search(&list, &x, MemberHeightCmp) != NULL) PrintLnCurrent(&list); else puts("その身長のデータはありません。"); break; case PRINT_ALL : /* 全ノードのデータを表示 */ Print(&list); break; case CLEAR : /* 全ノードを削除 */ Clear(&list); break; } } while (menu != TERMINATE); Terminate(&list);/* 線形リストの後始末 */ return 0; }
<質問>
ScanMember関数の中の処理について質問です。
char x[String_Max]の限界以上を入力したときに正しく入力されるまでループし、正しく入力されたときにループを抜け、範囲内の文字数を入力したname,vision,heightなどの情報を持ったtempが返るという動作が出来るようにしたいです。
<現状>
範囲内の文字数入力をした場合 ー> 正しく動作する
範囲以上の文字数入力をした場合 -> ループを抜け、name,vision,heightに値が入った後に
stack smashing detectedというエラーが発生する。
ご教授お願いします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。