質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

1823閲覧

構造体におけるポインタの使い方

h_proc

総合スコア68

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/02/16 09:02

編集2019/02/17 13:24

構造体いおいて、どのようにポインタを利用したらよいか分からず、いくつか質問させていただきたいと思います。一点目、構造体のリストへのポインタとキャラクタid1,id2を引数にして、キャラクタidの順番を入れ替える関数のコード書きました。id1.next=&id2; id2.next=id1;で表せると思ったのですが、エラーが起きてしまいます。どこが間違っているのでしょうか。

c

1#include<stdio.h> 2#include<string.h> 3#include<stdlib.h> 4#define STR_MAX 256 5#define WEPON 1 6#define AROMOR 2 7#define SHIELD 3 8 9struct equip {//装備 10 //メンバ変数 11 int type; //タイプ 12 char name[STR_MAX]; //名前 13 int point; //修正値 14}; 15 16typedef struct player { 17 int id; //キャラクタのID 18 char name[STR_MAX]; //名前 19 int level; //レベル 20 int power; //ちから 21 int protec; //まもり 22 struct equip wepon; //武器 23 struct equip armor;//鎧 24 struct equip shield;//盾 25 struct player *prev;//前のキャラクタへのポインタ 26 struct player *next;//次のキャラクタへのポインタ 27 28}player_t; 29 30void paty_change(player_t *play, int id1,int id2); 31 32void paty_change(player_t *play, int id1,int id2) { 33 id1->next = id2; 34 id2->next = id1; 35}

二点目、キャラクタへのポインタ*charaを構造体リストの最後に追加する関数(とその動作を確認するコード)を書きたいです。これであっているでしょうか。

c

1void paty_ch(player_t *play, char *chara); 2 3void paty_ch(player_t *play, char *chara) { 4 player_t *play=&chara; 5 play->next = &play; 6} 7

三点目、キャラクタのidと構造体リストへのポインタを受け取り、そのidをもつキャラクタへのポインタを返す関数(とその動作を確認するコード)を)書きたいです。ポインタを返すというのはどういう操作をすることなのでしょうか。また、どう書いたらよいか教えていただきたいです。

c

1char paty_id(player_t *play, int *id); 2 3char paty_id(player_t *play, int *id) { 4 play->id = &id; 5 return play->name; 6}

四点目、キャラクタへのポインタとstruct equipで表されるアイテムを受け取り、キャラクタにアイテムを装備させる関数(とその動作を確認するコードを))書きたいです。struct equipとplayer_tがどのような関係にあるか理解しておらず、どのようにして装備させたらよいか分かりません。

c

1void attach(player_t *play, struct equip wepon); 2 3void attach(player_t *play, struct equip wepon) { 4 5}

五点目、player_tへのポインタを受け取り、先頭から順にメンバリストの名前のみを表示させる関数を書きたいです。この時、受け取ったポインタが先頭かどうか確認させたいです。このようなコードをかいたのですが、無限ループのような状態になってしまいます。どこが間違っているのでしょうか。

c

1void paty(player_t *play){ 2 player_t *start; 3 int i = 0; 4 for (i = 0; play!=NULL; i++) { 5 if (i = 0) { 6 play = malloc(sizeof(player_t)); 7 start = play; 8 printf("名前を表示できませんでした。\n"); 9 } 10 else { 11 play->next = malloc(sizeof(player_t)); 12 play = play->next; 13 prinf("名前は%s\n", play->name); 14 } 15 }

まったく投げやりな質問になってしまって申し訳ございません。構造体のリストとポインタの関係だけでも教えていただけると嬉しいです。よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2019/02/16 10:16 編集

なぜ至るところでintのポインタを使っているのでしょう?・・・必要なのは構造体のポインタなのでは? また。IDに対応した構造体を探す処理が見受けられませんが?
jimbe

2019/02/16 11:44

'*' を付ければポインタ → ポインタは(intぐらいの?)数値 → int を付ける と誤解されているのではと思います. ポインタは, 分からない方にはなかなか難解だそうですので, なんともご説明が難しいですね.
h_proc

2019/02/16 11:59

構造体のポインタとはどのようなものでしょうか。intではなく、player_tを前につければいいのでしょうか。また、IDに対応した構造体というのは、IDに関する構造体を新たに定義しなおすということでしょうか。何もわかっておらず、質問内容が分かりづらくて、すみません。
jimbe

2019/02/16 12:58

構造体のポインタは '->' によって構造体の中身にアクセスできますが, int のポインタは(たとえその元が構造体のポインタだったとしても) '->' でアクセスできません. 構造体の中身にアクセスするのならば構造体のポインタにしなければなりません. 構造体の中身にアクセスしない(単に別の関数に渡すだけ等)のでしたら int のポインタでも記述できますが, 大変分かりにくくなりますし, 分かりにくければバグの元になり易いですので, 分かりやすく構造体のポインタに致します. cateye さんの言われたのは「IDに対応した構造体」では無く「IDに対応した構造体を探す処理」です. ご質問の3番目の関数のことと思います.
jimbe

2019/02/16 16:01

>void paty_ch(player_t *play, char *chara) { > player_t *play=&chara; > play->next = &play; >} chara は 確かにゲームにおきましては「キャラクタ」かも知れませんが, C言語の「キャラクタ」とは異なると思います. この場合, int * でも char * でも「構造体のポインタでは無い」という点では同じです.
jimbe

2019/02/16 16:21 編集

非常にまどろっこしくイライラされるかも知れませんが, つまりポインタとはそれほど(分からない方への説明が)面倒な存在であり, またC言語において(主に関数の引数や戻り値として)一般的かつ(特定の場面に)便利かつ(大抵の場面に)バグの元になり易い存在であり, 後発の言語にポインタが存在しない(隠蔽されている)理由であろうということを, まずご理解頂きたく思います.
cateye

2019/02/16 20:04

私のような(アセンブラぐらいしか手元になかったような)ロートルには、ポインタの概念はすんなり入っちゃいましたがw・・・ただ、Cのポインタ演算はムズい^^;
h_proc

2019/02/17 07:52

ありがとうございます。構造体のポインタについて勉強しなおします。
h_proc

2019/02/17 08:00

構造体のポインタとはたとえば、player_t *playのようなものでしょうか。
jimbe

2019/02/17 08:22 編集

player_t は構造体ですので, player_t *play と宣言された play 変数は「構造体のポインタ」と呼べると思います. もちろん正確には「player_t 構造体のポインタ」ということになります. これを(player_t はコードを見れば構造体と分かるので)縮めて「player_t のポインタ」との表現や, typedef struct player { … } player_t; ですので元の struct の名前から「player のポインタ」との表現もあるかと思います.
jimbe

2019/02/17 08:11

私も, (Z80 で)アセンブラを使っていましたので, 'ポインタ'…より'アドレス'のほうが先に馴染んでいました.
jimbe

2019/02/17 18:08

5番目のご質問を追加されましたが, 一旦開発の手を止められて, ポインタについて書籍等纏まった情報での学習を先にされる事をお勧め致します. ポインタを中途半端なご理解のまま続けられても次々とご質問が増えるだけに思われ, 1つの記事の中に幾つもご質問があっては, 回答も一度に全てには出来ませんでバラバラになってしまいます.
h_proc

2019/02/17 23:03

回答ありがとうございます。一度離れて勉強しなおします。
guest

回答5

0

struct player *prev;//前のキャラクタへのポインタ

struct player *next;//次のキャラクタへのポインタ

player のポインタになってますぜ
int でも intポインタでもありません

投稿2019/02/16 09:13

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

h_proc

2019/02/16 09:19

回答ありがとうございます。player のポインタとはどういうことでしょうか。これ自体で動くのでしょうか。
guest

0

ベストアンサー

c

1usr ~/Project/test/teratail % cat t.c 2#include <stdio.h> 3// 4#define STR_MAX 256 5// 6struct equip {//装備 7 //メンバ変数 8 int type; //タイプ 9 char name[STR_MAX]; //名前 10 int point; //修正値 11}; 12 13typedef struct player { 14 int id; //キャラクタのID 15 char name[STR_MAX]; //名前 16 int level; //レベル 17 int power; //ちから 18 int protec; //まもり 19 struct equip wepon; //武器 20 struct equip armor;//鎧 21 struct equip shield;//盾 22 struct player *prev;//前のキャラクタへのポインタ 23 struct player *next;//次のキャラクタへのポインタ 24 25}player_t; 26// 27player_t * get_player(player_t * root, int id) 28{ 29 player_t * ptr= root; // 最初のアドレス 30 while( ptr != NULL ){ // アドレスがNULLでない間 31 if( ptr->id == id ){// 同じIDなら検索をやめる 32 break; 33 } 34 ptr= ptr->next; // 次の構造体のアドレス 35 } 36 return ptr; 37} 38 39usr ~/Project/test/teratail % 40

プレイヤーの検索ルーチンだけですが、構造体のリスト(ポインタ)の使い方分かりますか?
同じIDのプレイヤーが見つかれば、その構造体のポインタ(アドレス)を返します。また、見つからない時は、ループの条件が偽(ptr==NULL)になるため、NULLが返ります。
一応コンパイルは通っています。

投稿2019/02/17 14:27

編集2019/02/17 14:33
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2019/02/17 14:30

呼び出し側がデータの参照だけなら「const player_t * get_player(player_t * root, int id)」にしましょうd^^
h_proc

2019/02/17 15:28

ありがとうございます。これを参考にさせていただき、もう少し考えてみます。
h_proc

2019/02/17 15:29

malloc関数で動的メモリを確保する必要はありますか。
cateye

2019/02/17 21:09 編集

malloc〜・・・それは、データを格納する段階の話で、ここではなくplayer_tを初期化(設定)する時の話です。配列(メモリ確保不要)にするか、動的に確保してリストに繋げるかはプログラム次第です。“双方向リスト c言語”で検索してみてください。データを設定、リストに繋げる、データを検索(上記)、データの変更、データの移動、データの削除などなど・・・各々に処理(関数)が必要になると思います。色々考えると頭が・・・なので必要な処理を細分化して、分けて考えるd^^
cateye

2019/02/18 02:14 編集

配列にする&削除も有る・・・とすると、構造体の中に削除された情報(有効/無効でも可)が必要になります。idを0にしてもいいけど・・・余談ですが、clangでコンパイルするとplayer_tのサイズは、1080バイトになります。・・・大きいのでポインタで管理するほうが楽かと・・・
jimbe

2019/02/18 01:35

幾つかの関数に現れている player_t * の引数が RPG におけるパーティのようですので, キャラクタの加入脱退に応じて増減は必要になりますが, そもそもパーティの表現としまして(一番普遍的と思われるドラクエをしたことが無いので Wizardry 的になりますが)もし『最大20人のキャラクタのリザーブから, 最大6人を選んでパーティを組む』タイプ(?)の仕様でしたら, パーティの配列が player_t *party[6]; になり, 関数の引数が player_t **party になり, 追加削除はポインタの代入(と前詰め?)で行う…様な気が致します(^^;
cateye

2019/02/18 01:52 編集

パーティについては、おっしゃるように最大値を設けて、(配列で)構造体のポインタを格納するのが正解かと。・・・某RPGではパーティ人数はMAX8となってました。なので、別段奇妙には思いません。・・・そうするとキャラクタ(パーティ?)の(マップ上の)位置情報もいるかもです?
jimbe

2019/02/18 02:22

同じ町に居るキャラクタだけパーティに入れられるようにする, 等という仕様ですね. >位置情報 : すみません完全に戯れ言です. 一応 h_proc さんが後日お読みになった時にご参考になればと, なるべく具体的に書かせて頂きましたが, cateye さんには今更と存じます. 失礼致しました.
cateye

2019/02/18 03:44

いえいえ気になさらずに、実務から遠ざかってかなり立ちますので、最新の情報や考え方は私にも有り難いです。・・・パーティそのものの構造体もいりますね・・・そうなると大変(-_-;);
h_proc

2019/02/20 12:45

ありがとうございます。引き続き、勉強を頑張ります。
guest

0

構造体のリストとポインタの関係

player_t 構造体は, 自分自身の型のポインタである prev と next を持っていることから, 双方向リストと呼ばれる構造の要素と思います.
その場合, これらは自身の前後の要素を指す(=ポイントする)ため, ポインタが使われます.

もしどうしてもピンと来ないとなりましたら, 構造体配列にしてしまうのも手かと思います.
RPG のパーティでしたら5~6人分程度と思われますし, リスト構造で手間取るよりも, より内容等に注力されたほうが良いかと思います.

投稿2019/02/16 17:49

jimbe

総合スコア12646

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

全面的に混乱が見られます。

前橋和弥氏のC言語ポインタ完全制覇を購入し読破してから改めて考えることをおすすめします。
新・標準プログラマーズライブラリ C言語 ポインタ完全制覇 | 前橋 和弥 |本 | 通販 | Amazon

投稿2019/02/16 11:14

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

h_proc

2019/02/17 07:53

回答ありがとうございます。参考にさせていただきたいと思います。
guest

0

id1.next=&id2; id2.next=id1;で表せる

関数 paty_change()の事でしょうか?
関数の引数を見ると、int id1,int id2 なんで、当然、id1->next, id1->next はエラーですね。(id1, id2 はポインタじゃない)

ポインタ*charaを構造体リストの最後に追加する

こちらは、play が引数とローカル変数にありますが、その意図は?
*chara は、charaが intのポインタなので、 intとなり、play->next (どっちのplayだ?) と型が一致しない。

そのidをもつキャラクタへのポインタを返す関数

まあ、
player_t * charaFunc() みたいな関数になるでしょうか?

まず、構造体のリスト云々以前に、Cのポインタと型(int, とか) の扱いから、確認すべきと思います。
ここの回答に書こうとすると結構な量になりそう。(自分には無理っぽい) 参考となるサイトとかあるか? それとも、書ける人がいるか?


[追記]
難しいだけはと、思い、一部だけ、ちょっと書いてみました。

C

1// play : パーティリスト 2// chara: 追加するメンバー名 3 4void paty_ch(player_t *play, char *chara) 5{ 6 player_t *newMember; 7 player_t *lastMember = play; // 最後のメンバー検索用 8 newMember = malloc(sizeof(player_t)); // 追加メンバー用の領域確保 9 strcpy(newMember->name, chara); // 最後のメンバー名を設定 10 // newMember->id = ?? 11 // newMember->level = ?? 12 // ... 以下、同様の他の変数はどうする?? 13 newMember->next = NULL; // 最後のメンバーのポインタは、NULLとする。 14 while (lastMember->next != NULL) { 15 lastMember = lastMember->next; 16 } 17 lastMember->next = newMember; 18 newMember->prev = lastMember; 19}

この構造体をどう使うかも分からないので、自分なら、こんな風に書くとしか、言えませんが。 (実際には、もう少し記述も必要で、エラーチェックも省いています。)

参考として。

投稿2019/02/16 09:38

編集2019/02/17 09:32
pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2019/02/16 11:15

普通に本一冊書くレベルになりそうなので既存の書籍へ誘導一択かなという感想。
h_proc

2019/02/16 12:02

ありがとうございます。書籍かサイトを探して、ポインタから勉強しなおします。
h_proc

2019/02/17 07:51

ありがとうございます。参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問