• ベストアンサー

C言語 初心者

コンパイルエラーはでないのに、 登録した単語を表示できません。 表示のところだと思うのですが・・・ /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <stdio.h> #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME]; /*単語*/ char wayaku[MAX_WAYAKU]; /*和訳*/ }words; /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。  */ /************************************************/ void tourokuword(words tango[], int tango_count) { char word[MAX_NAME]; /*単語の名前*/ char wa[MAX_WAYAKU]; /*単語の和訳*/ printf("[単語]:"); scanf("%s", word); /*単語を単語帳に登録*/ strcpy(tango[tango_count].name, word); printf("[和訳]:"); scanf("%s", wa); /*和訳を単語帳に登録*/ strcpy(tango[tango_count].wayaku, wa); } /***********************************************/ /*----- 単語の交換 -----*/ /***********************************************/ void swaps(words *x, words *y) { words temp = *x; strcpy(temp, *x); strcpy(*x, y); strcpy(*y, temp); } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの順番に表示する。  */ /***********************************************/ void printword(words tango[], int tango_count) { int i = 0; int j; puts("登録されている単語を表示します。\n"); for( i = 0; i < tango_count; i++){ for(j = i + 1; j < tango_count; j++){ if(strcmp(tango[i].name, tango[j].name) > 0){ swaps(&tango[i], &tango[j]); } } } for (i = 0 ; i < tango_count; i++) { printf("[単語]:%s\n",tango[i].name); /*単語の表示*/ printf("[和訳]:%s\n",tango[i].wayaku); /*和訳の表示*/ } } /****************/ /*--- メイン ---*/ /****************/ int main(void) { words tangochou[NUMBER]; /*単語帳に50件登録*/ int menu_num; /*メニュー番号*/ int slct_num; /*選択番号*/ int tango_count = 0; /*登録数のカウント*/ while(1){ /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf("1・・・登録. 2・・・表示. 3・・・終了.\n"); printf("メニュー番号を入力してください。:"); scanf("%d", &menu_num); /*メニュ番号の入力*/ if (menu_num > 0){ break; } }while(menu_num != 0); /*メニュ番号が該当しない時は再入力*/ switch (menu_num){ case 1 :/*--- メニュー 1:単語と和訳の登録 ---*/ while(1) { if (tango_count < NUMBER){ printf("英単語と和訳を入力してください。:\n"); /*単語と和訳の登録*/ tourokuword(tangochou, tango_count); tango_count++; }else { puts("50件以上です。\n"); return 0; /*50件以上は終了する*/ } /*登録を続けるか?*/ printf("続けますか【Yes・・・1/No…0】:"); scanf("%d", &slct_num); if(slct_num != 1){ /*0なら終了。1なら継続。*/ break; } } break; case 2 :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ printword(tangochou, tango_count); /*単語と和訳の表示*/ break; case 3 :/*--- メニュー 3:終了 ---*/ puts("終了します。\n"); return (0); default:/*--- メニュー 4:非メニュー番号の処理 ---*/ puts("メニュー番号が間違っています。"); break; } } return (0); }

質問者が選んだベストアンサー

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

>strcpy(temp, *x); >strcpy(*x, y); >strcpy(*y, temp); ここは完全に変ですね。 実行ファイルが出来ているとしても、ワーニングエラー出てませんか?出ていないとしたらコンパイラの種類を教えてください。 strcpyは文字列のコピー専用で'\0'を見つけたらコピーを終了します。この関数では構造体全部のコピーはできませんよ。 それと、そろそろバグは自分で原因を追求できるように訓練を始めましょう。デバッガを使ったり、色々なところにprintfを入れてみて変数値の変化を確かめたり自分で出来るようにならないとプログラマとして自立できませんよ。

hatenan114
質問者

補足

お世話になっています。 今、皆様のおかげで以下のソースまでたどり着きましたが、並べ替えが出来ていない状況です。少しアドバイスをお願いします。 /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <stdio.h> #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME]; /*単語*/ char wayaku[MAX_WAYAKU]; /*和訳*/ }words; /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。  */ /************************************************/ void tourokuword(words tango[], int tango_count) { char word[MAX_NAME]; /*単語の名前*/ char wa[MAX_WAYAKU]; /*単語の和訳*/ printf("[単語]:"); scanf("%s", word); /*単語を単語帳に登録*/ strcpy(tango[tango_count].name, word); printf("[和訳]:"); scanf("%s", wa); /*和訳を単語帳に登録*/ strcpy(tango[tango_count].wayaku, wa); } /***********************************************/ /*----- 単語の交換 -----*/ /***********************************************/ void swaps(words *x, words *y) { words temp = *x; strcpy(temp, *x); strcpy(*x, *y); strcpy(*y, temp); } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの並び替えて表示する */ /***********************************************/ void printword(words tango[], int tango_count) { int i = 0; int j; puts("登録されている単語を表示します。\n"); for( i = 1; i <= tango_count; i++){ for(j = - 1; j <= tango_count; j++){ if(strcmp(tango[i - 1].name, tango[i].name) > 0){ j = i - 1; swaps(&tango[i], &tango[j]); printf("[単語]:%s\n", tango[i].name); /*単語の表示*/ printf("[和訳]:%s\n", tango[i].wayaku); /*和訳の表示*/ } } } } /****************/ /*--- メイン ---*/ /****************/ int main(void) { words tangochou[NUMBER]; /*単語帳に50件登録*/ int menu_num; /*メニュー番号*/ int slct_num; /*選択番号*/ int tango_count = 0; /*登録数のカウント*/ while(1){ /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf("1・・・登録. 2・・・表示. 3・・・終了.\n"); printf("メニュー番号を入力してください。:"); scanf("%d", &menu_num); /*メニュ番号の入力*/ if (menu_num > 0){ break; } }while(menu_num != 0); /*メニュ番号が該当しない時は再入力*/ switch (menu_num){ case 1 :/*--- メニュー 1:単語と和訳の登録 ---*/ while(1) { if (tango_count < NUMBER){ printf("英単語と和訳を入力してください。:\n"); /*単語と和訳の登録*/ tourokuword(tangochou, tango_count); tango_count++; }else { puts("50件以上です。\n"); return 0; /*50件以上は終了する*/ } /*登録を続けるか?*/ printf("続けますか【Yes・・・1/No…0】:"); scanf("%d", &slct_num); if(slct_num != 1){ /*0なら終了。1なら継続。*/ break; } } break; case 2 :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ printword(tangochou, tango_count); /*単語と和訳の表示*/ break; 以下省略。

その他の回答 (14)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.15

「長さ」のところだけ生成させるんじゃなくって, %??s 全体を生成させれば (それにあわせてマクロの名前をわかりやすくすれば) いいと思うんだけど>#12.

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.14

ご参考: 文字列の読み込みに最大文字数を指定して scanf() を使い、ソートに qsort() を使って書き直しておきました。 がんばってください。 ======= /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #define TOSTRING_(s) #s #define TOSTRING(s) TOSTRING_(s) /* 一行読み飛ばす */ void skipln() { int c; while ((c = getchar()) != EOF) if (c == '\n') break; } #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME + 1]; /*単語*/ char wayaku[MAX_WAYAKU + 1]; /*和訳*/ }words; /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。  */ /************************************************/ void tourokuword(words tango[], int tango_count) { printf("[単語]:"); /*単語を単語帳に登録*/ scanf("%" TOSTRING(MAX_NAME) "s", tango[tango_count].name); skipln(); printf("[和訳]:"); scanf("%" TOSTRING(MAX_WAYAKU) "s", tango[tango_count].wayaku); skipln(); } /* words の比較関数(qsort()用)) */ int wcompare(const void *a, const void *b) { return strcmp(((const words *)a)->name, ((const words *)b)->name); } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの順番に表示する。  */ /***********************************************/ void printword(words tango[], int tango_count) { int i; puts("登録されている単語を表示します。\n"); for (i = 0 ; i < tango_count; i++) { printf("[単語]:%s\n",tango[i].name); /*単語の表示*/ printf("[和訳]:%s\n",tango[i].wayaku); /*和訳の表示*/ } } /****************/ /*--- メイン ---*/ /****************/ int main(void) { words tangochou[NUMBER]; /*単語帳に50件登録*/ int change = 0; /* 登録して変化したかを示す */ char menu_num; /*メニュー番号*/ char slct_num; /*選択番号*/ int tango_count = 0; /*登録数のカウント*/ while(1){ int ok = 0; /* 入力番号終了を示す */ /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf("1・・・登録. 2・・・表示. 3・・・終了.\n"); printf("メニュー番号を入力してください。:"); scanf(" %c", &menu_num); /*メニュ番号の入力*/ skipln(); switch (menu_num) { case '1': case '2': case '3': ok = 1; break; } }while(!ok); /*メニュ番号が該当しない時は再入力*/ switch (menu_num){ case '1' :/*--- メニュー 1:単語と和訳の登録 ---*/ while(1) { if (tango_count < NUMBER){ printf("英単語と和訳を入力してください。:\n"); /*単語と和訳の登録*/ tourokuword(tangochou, tango_count); change = 1; ++tango_count; }else { puts("51件以上です。\n"); return 1; /*51件以上は終了する*/ } /*登録を続けるか?*/ printf("続けますか【Yes・・・1/No…0】:"); scanf(" %c", &slct_num); skipln(); if(slct_num != '1'){ /*0なら終了。1なら継続。*/ break; } } break; case '2' :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ if (change) qsort(tangochou, tango_count, sizeof tangochou[0], wcompare); printword(tangochou, tango_count); /*単語と和訳の表示*/ change = 0; break; case '3' :/*--- メニュー 3:終了 ---*/ puts("終了します。\n"); return (0); default:/*--- メニュー 4:非メニュー番号の処理 ---*/ puts("メニュー番号が間違っています。"); break; } } return (0); }

hatenan114
質問者

お礼

回答ありがとうございます。 qsort についてべんきょうします。 またよろしくお願いします。

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.13

「プリプロセッサにフォーマット部の構築」じゃなくて、「プリプロセッサとコンパイラに…」か。。。失礼しました^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.12

 #define TOSTRING(s) TOSTRING_(s)  #define TOSTRING_(S) #s  #define MAX_NAME 20  #define MAX_WAYAKU 30  typedef struct {  char name[MAX_NAME + 1];  char wayaku[MAX_WAYAKU + 1];  }words;  で、マクロが数字のみで定義してあるとすれば、  void tourokuword( words tango[], int tango_count )  {   /* 単語,和訳を単語帳に登録 */   printf( "[単語]:" ); scanf( "%" TOSTRING(MAX_NAME) "s", tango[tango_count].name );   printf( "[和訳]:" ); scanf( "%" TOSTRING(MAX_WAYAKU) "s", tango[tango_count].wayaku );  } として、プリプロセッサにフォーマット部の構築をやらせますか?^^ わかりづらいので、お勧めはしませんけど^^ scanf() のフォーマットの s の最大文字数って、ピリオドの前じゃなかったでしたっけ?違ったかな? ピリオドの後は、代入する最小文字数っていうのかな?なので、ここでは、ピリオドはつけてません^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.11

あと、scanf() でフォーマット部にそのまま最大文字数を書きいれたときは、マクロの値を変更するときはフォーマット部も書き換えるように注意しましょう。フォーマット部を関数内で構築して scanf() に渡すようにすれば、不注意からの修正忘れエラーの防止になりますが。 なるほど。K&Rの第1版のころは、構造体の代入や構造体をそのまま関数に渡したり、関数から戻したりできませんでしたね。なつかしい^^ わたしは、一昔前に、K&Rの第2版で勉強しました。C99に対応した K&Rの第3版みたいなのは出版されてるのかしら?^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.10

あぁ、そういえば、そうですね。 swaps() では  ・yaemon_2006 さんの指摘されてる構造体のままのスワップする のと、文字列の読み込みでは、  ・Oh-Orange さんの指摘されている「最大文字数指定」で scanf() する のほうがわかりよいですね^^ 文字列を読み込みたいのは、「空白でない文字からなる文字列」なのか、「前後の空白を取り除いた、行全体の文字列」なのかよくわかりませんでしたけど、一応、余った文字は、行の最後まで読み飛ばしてあります^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.9

なんとなく「こうやりたい」のだろうと思って直してみました。 なので、出力ごとのソート(?)などはそのままです。 ==== /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <string.h> #include <ctype.h> void skipws() { int c; while ((c = getchar()) != EOF) { if (!isspace(c)) { ungetc(c, stdin); break; } } } void skipln() { int c; while ((c = getchar()) != EOF) if (c == '\n') break; } void get_string(int n, char *buf) { int c, m = 0; skipws(); while (m < n && (c = getchar()) != EOF) { if (isspace(c)) { ungetc(c, stdin); break; } buf[m++] = c; } buf[m] = '\0'; skipln(); } #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME + 1]; /*単語*/ char wayaku[MAX_WAYAKU + 1]; /*和訳*/ }words; /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。  */ /************************************************/ void tourokuword(words tango[], int tango_count) { printf("[単語]:"); /*単語を単語帳に登録*/ get_string(MAX_NAME, tango[tango_count].name); printf("[和訳]:"); get_string(MAX_WAYAKU, tango[tango_count].wayaku); } /***********************************************/ /*----- 単語の交換 -----*/ /***********************************************/ void swaps(words *x, words *y) { char ntmp[MAX_NAME + 1]; char wtmp[MAX_WAYAKU + 1]; strcpy(ntmp, x->name); strcpy(x->name, y->name); strcpy(y->name, ntmp); strcpy(wtmp, x->wayaku); strcpy(x->wayaku, y->wayaku); strcpy(y->wayaku, wtmp); } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの順番に表示する。  */ /***********************************************/ void printword(words tango[], int tango_count) { int i = 0; int j; puts("登録されている単語を表示します。\n"); for( i = 0; i < tango_count; i++){ for(j = i + 1; j < tango_count; j++){ if(strcmp(tango[i].name, tango[j].name) > 0){ swaps(&tango[i], &tango[j]); } } } for (i = 0 ; i < tango_count; i++) { printf("[単語]:%s\n",tango[i].name); /*単語の表示*/ printf("[和訳]:%s\n",tango[i].wayaku); /*和訳の表示*/ } } /****************/ /*--- メイン ---*/ /****************/ int main(void) { words tangochou[NUMBER]; /*単語帳に50件登録*/ char menu_num; /*メニュー番号*/ char slct_num; /*選択番号*/ int tango_count = 0; /*登録数のカウント*/ while(1){ int ok = 0; /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf("1・・・登録. 2・・・表示. 3・・・終了.\n"); printf("メニュー番号を入力してください。:"); scanf(" %c", &menu_num); /*メニュ番号の入力*/ switch (menu_num) { case '1': case '2': case '3': ok = 1; break; } }while(!ok); /*メニュ番号が該当しない時は再入力*/ switch (menu_num){ case '1' :/*--- メニュー 1:単語と和訳の登録 ---*/ while(1) { if (tango_count < NUMBER){ printf("英単語と和訳を入力してください。:\n"); /*単語と和訳の登録*/ tourokuword(tangochou, tango_count); ++tango_count; }else { puts("51件以上です。\n"); return 1; /*51件以上は終了する*/ } /*登録を続けるか?*/ printf("続けますか【Yes・・・1/No…0】:"); scanf(" %c", &slct_num); if(slct_num != '1'){ /*0なら終了。1なら継続。*/ break; } } break; case '2' :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ printword(tangochou, tango_count); /*単語と和訳の表示*/ break; case '3' :/*--- メニュー 3:終了 ---*/ puts("終了します。\n"); return (0); default:/*--- メニュー 4:非メニュー番号の処理 ---*/ puts("メニュー番号が間違っています。"); break; } } return (0); }

hatenan114
質問者

お礼

回答有難うございます。 このソースを少し解読してみます。 これからよろしくお願いします。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.8

★追記。 ・scanf() 関数の書式列に入力可能な文字数を指定しておくと安全になります。  例えば  scanf( "%.19s", word );  とします。これが出来るため直接構造体のメンバを引数に渡すことも可能です。  つまり  void tourokuword( words tango[], int tango_count )  {   /* 単語,和訳を単語帳に登録 */   printf( "[単語]:" ); scanf( "%.19s", tango[tango_count].name );   printf( "[和訳]:" ); scanf( "%.49s", tango[tango_count].wayaku );  }  こんな感じでも行えます。 ・以上。

hatenan114
質問者

お礼

ありがとうございます。 勉強なります。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.7

★構造体はそのまま代入演算子で行えます。 ・回答者 No.3 さんの回答通りです。  関数を利用するなら回答者 No.4 さんのアドバイスにある memcpy() 関数で出来ます。  今回は swaps() 関数の >strcpy(temp, *x); >strcpy(*x, y); >strcpy(*y, temp);  の3行を  temp = *x;  *x = *y;  *y = temp;  の3行にすることで上手くいきます。 ・ちなみに >words temp = *x;  ↑  既に自分で構造体のコピーを代入演算子を用いて行っていますよ。  これの書き方で良かったわけです。 ・あと printword() 関数はバブルソートされて表示されますね。  ソートする部分は関数で分けてみてはどうかな。  例えば  void sortword( words tango[], int tango_count );  という関数を作ってみる。  そして表示だけの関数を  void printword( words tango[], int tango_count );  という関数にする。 ・以上。参考に。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.6

hana-hana3さん、ちゃんとtypedefしたwordsは使われてますよ。その問題はなさそうです。 補足として、ここまで作ったなら文字列長のガードもした方が良さそうですね。 19文字と49文字の文字列長の制限を加えることをお勧めします。入力時のバッファもギリギリだと危険なので余裕を見たほうが良いでしょう。

関連するQ&A