- ベストアンサー
構造体配列とポインタについて
いつもお世話になっています。 皆様には、本当にお世話になっています。 先日、皆様にアドバイスをいただいたのですが、私の勉強不足で結局・・・並び替えて表示できなかったです。 大変申し訳ないのですが、どこがダメなのか教えてください。 /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <string.h> #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME]; /*単語*/ char wayaku[MAX_WAYAKU]; /*和訳*/ }words; /***********************************************/ /*----- 単語の交換 -----*/ /***********************************************/ void swaps(words x, words y) { words temp = x; temp = x; x = y; y = temp; } /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。 */ /************************************************/ void tourokuword(words tango[], int tango_count) { char word[MAX_NAME]; /*単語の名前*/ char wa[MAX_WAYAKU]; /*単語の和訳*/ int i = 0; int j; printf("[単語]:"); scanf("%s", word); /*単語を単語帳に登録*/ strcpy(tango[tango_count].name, word); printf("[和訳]:"); scanf("%s", wa); /*和訳を単語帳に登録*/ strcpy(tango[tango_count].wayaku, wa); for( i = 0; i < tango_count; i++){ if(strcmp(tango[tango_count].name, tango[i].name) > 0){ swaps(tango[tango_count], tango[i]); } } } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの並び替えて表示する */ /***********************************************/ void printword(words tango[], int tango_count) { int i = 0; 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 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); }
- みんなの回答 (15)
- 専門家の回答
質問者が選んだベストアンサー
>回答についてですが、質問があります。 >void swaps(words *x, words *y) >と、 >swaps(&tango[tango_count], &tango[i]); >は、もしかして、ポインタのポインタではないですよね? 違いますよ。ポインタのポインタはwords **xと書きます。 今回は必要ないので使っていません。今回のは、だたの構造体のポインタです。 >void swaps(words *x, words *y) >と、 >swaps(&tango[tango_count], &tango[i]); >修正し、実行してみましたが、並び替えられていません?? >どこがおかしいのでしょうか? これを↓表示の直前に移しましょう。その方が入力直後にソートするよりもプログラム的に簡単で分かりやすいと思います。それがうまく動いたら入力直後のソートに挑戦してみたらどうでしょう? for( i = 0; i<(tango_count-1); i++){ for( j = (i+1); j<tango_count ; j++ ) { if(strcmp(tango[i].name, tango[j].name) > 0){ swaps(&tango[i], &tango[j]); } } 元々書いていたのに近いものにしてみました。 このソートは、一番シンプルなソートの方法のうちの1つです。 まず、このソートを使いこなしましょう。 最後にソートの種類とアルゴリズムを紹介。 http://www.u-gakugei.ac.jp/~miyadera/LECTURE/SortAnim/ExAlgorithm.html http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%BC%E3%83%88 http://www1.cts.ne.jp/~clab/Contents/Sortindex.html
その他の回答 (14)
- mikaemi
- ベストアンサー率50% (33/65)
あっ、ごめんなさい。hatenan114 「さん」が抜けてました^^;
お礼
mikaemiさん、このたびは本当にありがとうございます。 これまでにみなさんが回答してくれたものを、確実に身に付けていきます。 これからも宜しくお願いします。
- mikaemi
- ベストアンサー率50% (33/65)
hatenan114は、既登録の単語はソートされてることを前提に、登録のところで、新しく登録する単語を一つだけ一重ループで挿入ソートっぽく挿入したいんだよね?^^
- Oh-Orange
- ベストアンサー率63% (854/1345)
/********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <string.h> #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME]; /*単語*/ char wayaku[MAX_WAYAKU]; /*和訳*/ } words; /************************/ /*----- 単語の交換 -----*/ /************************/ void swaps( words *x, words *y ) { words temp; temp = *x; *x = *y; *y = temp; } /**************************/ /*----- 単語のソート -----*/ /**************************/ void sortword( words tango[], int tango_count ) { int i, j; for ( i = (tango_count - 1) ; i > 0 ; i-- ){ for ( j = 0 ; j < i ; j++ ){ if ( strcmp(tango[j].name,tango[j + 1].name) > 0 ){ swaps( &tango[j], &tango[j + 1] ); } } } } /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。 */ /************************************************/ void tourokuword( words tango[], int tango_count ) { char buff[ 256 ]; /*単語を単語帳に登録*/ printf( "[単語]:" ); scanf( "%s", buff ); buff[ MAX_NAME - 1 ] = '\0'; strcpy( tango[tango_count].name, buff ); /*和訳を単語帳に登録*/ printf( "[和訳]:" ); scanf( "%s", buff ); buff[ MAX_WAYAKU - 1 ] = '\0'; strcpy( tango[tango_count].wayaku, buff ); } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数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 ); /*和訳の表示*/ printf( "\n" ); } } /****************/ /*--- メイン ---*/ /****************/ int main( void ) { words tangochou[ NUMBER ]; /*単語帳に50件登録*/ int menu_num; /*メニュー番号*/ int tango_count = 0; /*登録数のカウント*/ do { /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf( "\n" ); printf( "1・・・登録. 2・・・表示. 3・・・終了.\n" ); printf( "メニュー番号を入力してください。:" ); scanf( "%d", &menu_num ); /*メニュ番号の入力*/ } while ( menu_num <= 0 ); /*メニュ番号が該当しない時は再入力*/ switch ( menu_num ){ case 1:/*--- メニュー 1:単語と和訳の登録 ---*/ if ( tango_count >= NUMBER ){ puts( "50件以上です。\n" ); return 1; /*50件以上は終了する*/ } printf( "\n英単語と和訳を入力してください。:\n" ); /*単語と和訳の登録*/ tourokuword( tangochou, tango_count ); tango_count++; break; case 2 :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ sortword( tangochou, tango_count ); /*単語と和訳のソート*/ printword( tangochou, tango_count ); /*単語と和訳の表示*/ break; case 3 :/*--- メニュー 3:終了 ---*/ puts("終了します。\n"); break; default:/*--- メニュー 4:非メニュー番号の処理 ---*/ puts( "メニュー番号が間違っています。" ); break; } } while ( menu_num != 3 ); return 0; } ※インデント部は全角空白文字です。注意。 以上。
お礼
Oh-Orangeさん、このたびは本当にありがとうございます。 これまでにみなさんが回答してくれたものを、確実に身に付けていきます。 これからも宜しくお願いします。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★すべてのソースを手直しして動くようにしました。 ・何も修正しないでコンパイルするとワーニング(警告)が3つ表示されました。 >単語帳.cpp(40) : warning C4101: 'j' : ローカル変数は 1 度も使われていません。 >単語帳.cpp(87) : warning C4127: 条件式が定数です。 >単語帳.cpp(101) : warning C4127: 条件式が定数です。 ↑ tourokuword() 関数の j 変数は使っていないので削除すべき。 87、101行のはいずれも while(1) としているので for ( ; ; ) として無限ループを組むべし。 ・次に修正した関数と内容を解説。 (1)swaps() 関数に関しては他の回答者さんのアドバイス通りです。そちらを参考に。 (2)sort() 関数を追加しました。これがソート処理です。 (3)sort() 関数より tourokuword() 関数は登録するたびにソートしないようにしています。 scanf() 関数で直接構造体に文字列を入れている点に注目して下さい。 (4)printword 関数は int i = 0 の部分を int i; に修正しました。あと改行を入れました。 (5)main() 関数の while(1) を do-while に修正しました。 (6)main() 関数の do{ … } while ( menu_num != 0 ); を修正しました。break 部も削除。 (7)main() 関数の『単語と和訳の登録』部分を修正しました。続けますかとは表示し内容にした。 (8)main() 関数の『単語と和訳の表示』部分の前でソートをしています。その後表示。 (9)main() 関数の『メニュー終了』部分はメッセージのみで break します。その後do-while で抜ける。 以上の9箇所を修正しました。 次の回答でソースを載せますのでチェックしてみて下さい。 特にソート部分(swaps,sortword)と main() 関数全体を見て下さい。 ・以上。
- mikaemi
- ベストアンサー率50% (33/65)
じゃあ、登録のところで、こうしますか? for( i = tango_count; i > 0; --i){ if(strcmp(tango[i-1].name, tango[i].name) > 0){ swaps(&tango[i-1], &tango[i]); } }
- mikaemi
- ベストアンサー率50% (33/65)
ん?登録のところで並び替えるのも、表示のところで並び替えるのも同じじゃないの?登録時は一個ずつ入れるので「挿入ソート」をつかって、表示の際は「シェルソート」使うとか? まぁそのうち、こなれてきてわかるようになると思いますよ。K&Rなどのよい言語の本と「アルゴリズムとデータ構造」などの本をじっくり理解していくのが、結局、早道かもしれませんが。。がんばってください^^
- mikaemi
- ベストアンサー率50% (33/65)
きゃはは^^ hatenan114 さん、おもしろいね^^ http://oshiete1.goo.ne.jp/qa3293885.html に残ってますよ(笑)
補足
ありがとうございます!!! でも・・・今回のソースは表示のところで並び替えず、登録時に並び替えたものなんです。 はぁ、7月からC言語をはじめたのですが、毎日が格闘です。
- mikaemi
- ベストアンサー率50% (33/65)
hatenan114 さんが最初していたように、ソートするループを2重にしてください^^
補足
ループの部分がおかしいのですか?? 前のは、上書きしてしまい、わすれてしまいました。 すみません。
- chie65536
- ベストアンサー率41% (2512/6032)
swaps(tango[tango_count], tango[i]); と呼び出すと、 void swaps(words x, words y) に来る前に、 ・メモリ上にxが作られ、xにtango[tango_count]がコピーされる ・メモリ上にyが作られ、xにtango[i]がコピーされる と言う事が起きます。 で、xとyを入れ替えても、コピーが入れ替わるだけです。 ・その1 呼び出す部分を swaps(&tango[tango_count],&tango[i]); にして、関数を void swaps(words *x, words *y) { words temp = *x; *x = *y; *y = temp; } にする。 ・その2 呼び出す部分を swaps(tango,tango_count,i); にして、関数を void swaps(words tango[],int x, int y) { words temp = tango[x]; tango[x] = tango[y]; tango[y] = temp; } にする。 ・その3 インデックス配列を作成し、実体は入れ替えせず、インデックス配列のみを入れ替える。表示する時は、実体の順で表示せず、インデックス配列の順で表示する。 (このプログラムは回答に書きません。自作してみましょう) インデックス配列を用いる理由は以下の通り。 一番先頭に来る単語を最後に登録したらどうなるでしょう。50バイトもある配列が、49回も入れ替えされます。 単語数が50個なら問題無いですが、単語数が5000とかになったら? 構造体サイズが50バイトなら問題無いですが、文字数を増やして構造体が500バイトになったら?
お礼
ありがとうございます。 しかし、 修正し、実行してみましたが、並び替えられていません?? どこがおかしいのでしょうか?
- zwi
- ベストアンサー率56% (730/1282)
>void swaps(words x, words y) >{ >words temp = x; > >temp = x; >x = y; >y = temp; >} なるほどわかりました。 原因はですね。値渡しとポインタによる参照渡しの違いを理解することが必要です。 >void swaps(words x, words y) と書くと呼び元の swaps(tango[tango_count], tango[i]); の実体をswaps関数に渡すのではなく、中身をコピーした新たなx,y構造体を作って渡すという意味なります。 つまり呼び出し時に、 words x = tango[tango_count]; words y = tango[i]; を暗黙に実行してコピーしています。 ですので、いくらx,yの中身を入れ替えてもコピーですので、元のtango[]側には影響がありません。 この場合は、 void swaps(words *x, words *y) と書いて swaps(&tango[tango_count], &tango[i]); で呼んでやるとポインタ渡しで実体のアドレスを受け渡すことが出来ます。ポインタの先はコピーではなく実体ですから、実体を書き換えることが出来るわけです。 void swaps(words *x, words *y) { words temp = *x; ポインタ先のxの実体をtempにコピー。 //temp = *x; ← 上の宣言で実行しているので不要です。 *x = *y; ← ポインタ先のyの実体をxの実体にコピー。 *y = temp; ← tempをポインタ先のyの実体にコピー。 } で交換がうまく出来るはずです。 前回は、色々いっぱい情報が入ってきて混乱しましたか? 他の人の意見も貴重なものが沢山ありましたので、1つずつ自分のものにしていってください。
お礼
本当に zwi 様には、頭があがらないです。 ありがとうございます。 一生懸命頑張りますので、宜しくお願いします。 回答についてですが、質問があります。 void swaps(words *x, words *y) と、 swaps(&tango[tango_count], &tango[i]); は、もしかして、ポインタのポインタではないですよね?
補足
void swaps(words *x, words *y) と、 swaps(&tango[tango_count], &tango[i]); 修正し、実行してみましたが、並び替えられていません?? どこがおかしいのでしょうか?
- 1
- 2
お礼
zwiさん、このたびは本当にありがとうございます。今日からは入門書を最初からしていきます。 次は社員名簿をリスト構造を使って作る予定なので、また宜しくお願いします。 これまでにみなさんが回答してくれたものを、確実に身に付けていきます。