• ベストアンサー

初心者です。

いつもお世話になっています。 現在、ポインタと構造体と配列をつかって、構造体を使った単語帳を作成しています。以下のソースで、行き詰まってしまいした。 質問内容としては、今のソースから、単語と意味を登録するにはどうすればいいでしょうか?できれば、ポインタの使用時には、詳しく教えていただけないでしょうか。宜しくお願いします。 * 英単語辞書の登録と表示 */ #include <stdio.h> #define NUMBER 50 /*登録数*/ /*--- 単語帳の構造体 ---*/ struct words{ char name[20]; char wayaku[50]; }; /*--- 単語と和訳の登録 ---*/ /*--- 登録された単語を表示する ---*/ int main(void) { struct words name[] = {0}; struct words wayaku[] = {0}; char word = 0, wa = 0; char *p, *q; int menu; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 :printf("英単語を登録してください。:"); scanf("%s", word); p = &word; putchar('\n'); printf("和訳を入力してください。:"); scanf("%s", wa); q = &wa; putchar('\n'); break; case 2 :puts("登録されている単語を表示します。\n"); break; case 3 :puts("終了します。\n"); return (0); default :puts("メニュー番号が間違っています。"); break; } } ; return (0); }

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

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

大分よくなってきました! まだ、構造体のメンバ(タグ)の扱いが混乱しているようです。 >/*--- 単語と和訳の登録 ---*/ >void touroku_word(words *tango) > strcpy(tango, word); > strcpy(tango, wa); tangoは構造体のポインタなので文字列をコピーできません。正確に言うと今のプログラムではtangoは、tangochou[0]の構造体のポインタで、何単語目であろうと常にtangochou[0]のポインタです。 tango[i].nameと表示のときに書いてますから、同じことを値を入れるときにも書くだけですよ。 それと入力した単語の数をカウントアップしている箇所が見当たりません。 >/*--- 登録された単語を表示する ---*/ >void print_word(words *tango, int *num) > for (i ; i < *num; i++) { numは値を書き換える必要がないなら、ポインタで渡す必要はありません。 > n = &i; iをnポインタに置き換える必要はまったくありません。 int n=0;で問題ないです。 > switch (menu){ > case 1 : > while(1) { while(1) {は、ループにする必要がないので外しましょう。 > if (i <= NUMBER){ 50個のガードは、よく気づきました! しかし、これだと配列要素数をオーバーします。よく考えてみてください。配列は0から始まりますよ。

hatenan114
質問者

お礼

ありがとうございます。 完成いたしました。 /* 英単語辞書の登録と表示 */ #include <stdio.h> #define NUMBER 50 /*登録数*/ /*--- 単語帳の構造体 ---*/ typedef struct { char name[20]; char wayaku[50]; }words; /*--- 単語と和訳の登録 ---*/ void touroku_word(words *tango, int num) { char word[20]; char wa[50]; printf("[単語]:"); scanf("%s", word); strcpy(tango[num].name, word); printf("[和訳]:"); scanf("%s", wa); strcpy(tango[num].wayaku, wa); } /*--- 登録された単語を表示する ---*/ void print_word(words *tango, int num) { int i = 0; puts("登録されている単語を表示します。\n"); for (i ; i < num; i++) { printf("[単語]:%s\n",tango[i].name); printf("[和訳]:%s\n",tango[i].wayaku); } } int main(void) { words tangochou[NUMBER]; int menu, slct; int i = 0, num = 0; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 : while(1) { if (i < NUMBER){ printf("英単語と和訳を入力してください。:\n"); touroku_word(tangochou, num); num++; }else { puts("50件以上です。\n"); return(0); } printf("続けますか【Yes・・・1/No…0】:"); scanf("%d", &slct); if(slct != 1) break; } case 2 :print_word(tangochou, num); break; case 3 :puts("終了します。\n"); return (0); default :puts("メニュー番号が間違っています。"); break; } } return (0); }

その他の回答 (5)

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

>scanf時のwordとmainのstruct words word のwordが重なるのはだめなような気がするのですが・・・? その通りですね。struct words TangoChou[2];なんてどうでしょうか? >void touroku_word(char *p) >{ >if (p == '0'){ >return; >} >strcpy(word[name],p); >} ここが全く違います。 ポインタと配列の使い方が違いますね。 それと >struct words word[2]; をtouroku_word関数に受け渡していないのと、そもそもtouroku_word関数を呼び出していませんよね。変数のスコープも覚えないといけませんね。 ここ↓の16章まで復習してみてください。 http://homepage3.nifty.com/mmgames/c_guide/ 全体のプログラムを書く前に、まず構造体配列の使い方を覚えましょう。 struct words TangoChou[2]; の各項目にすべて代入するだけのプログラムを書いてみてください。 色々調べて、これぞ正解だというものをじっくり考えてみてください。 今、一足飛びにプログラムを書くのは無理がありますから、基礎固めをしっかりとやりましょう!

hatenan114
質問者

お礼

丁寧に回答していただきありがとうございます。 以下のソースでどうでしょうか? /* 英単語辞書の登録と表示 */ #include <stdio.h> #define NUMBER 50 /*登録数*/ /*--- 単語帳の構造体 ---*/ typedef struct { char name[20]; char wayaku[50]; }words; /*--- 単語と和訳の登録 ---*/ void touroku_word(words *tango) { char word[20]; char wa[50]; printf("[単語]:"); scanf("%s", word); strcpy(tango, word); printf("[和訳]:"); scanf("%s", wa); strcpy(tango, wa); } /*--- 登録された単語を表示する ---*/ void print_word(words *tango, int *num) { int i = 0; puts("登録されている単語を表示します。\n"); for (i ; i < *num; i++) { printf("[単語]:%s\n",tango[i].name); printf("[和訳]:%s\n",tango[i].wayaku); } } int main(void) { words tangochou[NUMBER]; int menu, *n; int i = 0; n = &i; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 : while(1) { if (i <= NUMBER){ printf("英単語と和訳を入力してください。:\n"); touroku_word(tangochou); break; }else { puts("50件以上です。\n"); return(0); } } case 2 :print_word(tangochou, n); break; case 3 :puts("終了します。\n"); return (0); default :puts("メニュー番号が間違っています。"); break; } } return (0); }

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

>struct words { >char name[20]; >char wayaku[50]; >int count[NUMBER]; >}; countは構造体の外にあるべきですね。 構造体配列の使用数をカウントして覚えるだけなので、配列である必要もありません。 >struct words word ; >word.name = a; >word.wayaku = b; 残念ながら、文字列も文字配列も理解できていません。 実体のある文字配列に代入できるのは次の形のいずれかだけです。 (1)その1 word.name[0] = 'a'; word.name[1] = 'b'; word.name[2] = 'c'; word.name[3] = '\0'; (2)その2 strcpy(word.name,"abc"); その1と2の結果は同じになります。これが理解できますか? 文字列も文字配列であることを理解してください。 これが理解できたら struct words word [2]; のすべての要素に代入してみましょう。

hatenan114
質問者

お礼

修正と追加をしてみました。 いかがでしょうか? 疑問点があります。 scanf時のwordとmainのstruct words word のwordが重なるのはだめなような気がするのですが・・・? /* 英単語辞書の登録と表示 */ #include <stdio.h> #define NUMBER 50 /*登録数*/ /*--- 単語帳の構造体 ---*/ struct words { char name[20]; char wayaku[50]; }; /*--- 単語と和訳の登録 ---*/ void touroku_word(char *p) { if (p == '0'){ return; } strcpy(word[name],p); } /*--- 登録された単語を表示する ---*/ int main(void) { struct words word[2]; struct words[2]; char wa[50]; char *p, *q; int menu; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 :printf("英単語を登録してください。:"); scanf("%s", word); p = &word; putchar('\n'); printf("和訳を入力してください。:"); scanf("%s", wa); q = &wa; putchar('\n'); break; case 2 :puts("登録されている単語を表示します。\n"); break; case 3 :puts("終了します。\n"); return (0); default :puts("メニュー番号が間違っています。"); break; } } return (0); }

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

#1のzwiです。 >struct words name[NUMBER] = {0}; >struct words wayaku[NUMBER] = {0}; エラーの情報が貼り付けてもらっていないので、正確な場所がわからないですが、たぶんここです。初期値の与え方が間違っています。 ですが、エラーの解説の以前にstruct wordsは構造体なので、nameとwayakuの要素を含んでいることを理解してください。#1で構造体を理解していないと言ったのはそのためです。2つ宣言する必要はありません。 プログラム全体を書く前に1つづ解決して前に進むクセをつけましょう。 機能の理解→プログラムの設計→プログラミングの段階を踏まないと書いたプログラム全体が無駄になるばかりです。 今回は、まず構造体を理解してください。 まず単純に構造体の変数を宣言してみましょう。 struct words word; と書いてみてください。 このwordという構造体に値をどうやって代入しますか? 答えが書けますか?

hatenan114
質問者

お礼

ありがとうございます。 頑張りますので、何卒宜しくお願いします。

hatenan114
質問者

補足

親切に教えていただきありがとうございます。 以下のようになりました。が、いかがでしょうか?? /*--- 単語帳の構造体 ---*/ struct words { char name[20]; char wayaku[50]; int count[NUMBER]; }; int main(void) { struct words word ; word.name = a; word.wayaku = b; word.count = 1;

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

★アドバイス >単語と意味を登録するにはどうすればいいでしょうか?  ↑  これを考える前に  (1)構造体の配列の宣言の仕方。  (2)scanf() 関数の使い方。  (3)セミコロンの意味。  を復習して下さい。  (1)(2)は既に回答者 No.1(zwi) さんから指摘されている通りですね。 ・(3)は無限ループを構成している while(1) のブロックの最後に『;』文字があります。  動作的には空文として機能するため問題はありませんが、不必要に『}』文字の次に  コロン文字『;』をつけてはいけません。取り除いて下さい。if、else ではエラーに  なります。while 文が運良く空文として動作してエラーにならないだけです。注意。  ※もしかして最初は do-while で書いていたのか?while にするときには取り除こう。 本題: >単語と意味を登録するにはどうすればいいでしょうか?  ↑ ・それでは手順を文章で。  (1)scanf() からメニュー番号を取得。  (2)登録件数のカウンタが NUMBER 個を越えたら『これ以上登録できない』と表示。  (3)単語登録は『struct words』構造体の『name』メンバに scanf() から入力。  (4)和訳登録は『struct words』構造体の『wayaku』メンバに scanf() から入力。  (5)登録した件数をカウントする。  (6)break して switch 文を抜ける。  まずは構造体の宣言をちゃんと NUMBER 個分だけ確保して下さい。  ポインタの前に構造体を復習するわけ。 ・それから scanf() 関数で文字列を受け取るには受け取るための領域(文字型配列)を  指定します。このとき直接・構造体の『name』とか『wayaku』を渡すと入力文字数が  越えてしまうと困るので一時的に大きい領域 char input[ 256 ] とかの領域を渡すか、  scanf( "%.19s", data[i].name ); というように書式制御文字列に入力できる文字数を書きます。  scanf() の使い方でピリオド文字の後の数字が入力可能なバイト数(文字数でない)になります。  char name[ 20 ] なので \0 文字を引いた 19 という事です。  char wayaku[ 50 ] の場合は \0 文字を引いた 49 という数にすれば良いでしょう。  とにかく構造体、scanf()、登録された件数のカウンタ変数を用意して下さい。 ・以上。

hatenan114
質問者

お礼

回答していただき、有難うございます。

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

勉強中に人に、そのものの答えを書いても理解度あがると思えないのでヒントだけ書きます。 ●struct wordsの配列が必要です。この場合NUMBERの数だけ確保します。 それと struct words name[] = {0}; struct words wayaku[] = {0}; が矛盾します。nameとwayakuの情報を操作する構造体struct wordsなのにnameとwayakuと言う名前で各々の配列確保、それも配列要素を1個だけは意味がありません。 ●scanf("%s", word); char word = 0 %s書式は文字列を取り込むためのものですから、受け取る変数は実体のある文字の配列以外は書いてはいけません。 char word[100]; なら正解です。 ●英単語帳の管理。 何番目の配列までを使ったかをカウントするカウンタを用意します。 それを配列の添え字に使って登録する毎にカウントアップします。 表示する場合は、0からさっき使ったカウンタ番目-1までを表示することで登録されている英単語帳が表示できます。 ●全体的に文字列、配列、ポインタの理解が不足しています。 その説明はここで書ききれる情報量じゃありませんので、ちゃんとした入門書を読んだほうが良いと思います。 一応ポインタの入門が書かれたサイトを紹介しておきます。 http://itpro.nikkeibp.co.jp/article/COLUMN/20061206/256198/?ST=develop これを読んだ上でさらに疑問が残るようなら、ポインタだけの入門書も発売されていますので、購入を検討してみてください。

hatenan114
質問者

補足

回答ありがとうございます。 以下のように修正してみたのですが、エラーがでます。 どの箇所が間違っているのでしょうか? /*--- 単語帳の構造体 ---*/ struct words{ char name[20]; char wayaku[50]; }; /*--- 単語と和訳の登録 ---*/ /*--- 登録された単語を表示する ---*/ int main(void) { struct words name[NUMBER] = {0}; struct words wayaku[NUMBER] = {0}; char word[20]; char wa[50]; char *p, *q; int menu; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 :printf("英単語を登録してください。:"); scanf("%s", word); p = &word; putchar('\n'); printf("和訳を入力してください。:"); scanf("%s", wa); q = &wa; putchar('\n');