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

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

ただいまの
回答率

90.45%

  • C

    4674questions

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

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

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 412

h_proc

score 32

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

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define STR_MAX 256
#define WEPON 1
#define AROMOR 2
#define SHIELD 3

struct equip {//装備
    //メンバ変数
    int type;            //タイプ
    char name[STR_MAX]; //名前
    int point;        //修正値
};

typedef struct player {
    int id;             //キャラクタのID
    char name[STR_MAX]; //名前
    int level;          //レベル
    int power;          //ちから
    int protec;         //まもり
    struct equip wepon; //武器
    struct equip armor;//鎧
    struct equip shield;//盾
    struct player *prev;//前のキャラクタへのポインタ
    struct player *next;//次のキャラクタへのポインタ

}player_t;

void paty_change(player_t *play, int id1,int id2);

void paty_change(player_t *play, int id1,int id2) {
    id1->next = id2;
    id2->next = id1;
}


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

void paty_ch(player_t *play, char *chara);

void paty_ch(player_t *play, char *chara) {
    player_t *play=&chara;
    play->next = &play;
}


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

char paty_id(player_t *play, int *id);

char paty_id(player_t *play, int *id) {
    play->id = &id;
    return play->name;
}


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

void attach(player_t *play, struct equip wepon);

void attach(player_t *play, struct equip wepon) {

}


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

void paty(player_t *play){
    player_t *start;
    int i = 0;
    for (i = 0; play!=NULL; i++) {
        if (i = 0) {
            play = malloc(sizeof(player_t));
            start = play;
            printf("名前を表示できませんでした。\n");
        }
        else {
            play->next = malloc(sizeof(player_t));
            play = play->next;
            prinf("名前は%s\n", play->name);
        }
    }


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • jimbe

    2019/02/17 17:11

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

    キャンセル

  • jimbe

    2019/02/18 03:08

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

    キャンセル

  • h_proc

    2019/02/18 08:03

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

    キャンセル

回答 5

+2

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/16 18:19

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

    キャンセル

checkベストアンサー

+1

usr ~/Project/test/teratail % cat t.c
#include <stdio.h>
//
#define STR_MAX 256
//
struct equip {//装備
    //メンバ変数
    int type;            //タイプ
    char name[STR_MAX]; //名前
    int point;        //修正値
};

typedef struct player {
    int id;             //キャラクタのID
    char name[STR_MAX]; //名前
    int level;          //レベル
    int power;          //ちから
    int protec;         //まもり
    struct equip wepon; //武器
    struct equip armor;//鎧
    struct equip shield;//盾
    struct player *prev;//前のキャラクタへのポインタ
    struct player *next;//次のキャラクタへのポインタ

}player_t;
//
player_t * get_player(player_t * root, int id)
{
    player_t * ptr= root;   // 最初のアドレス
    while( ptr != NULL ){   // アドレスがNULLでない間
        if( ptr->id == id ){// 同じIDなら検索をやめる
            break;
        }
        ptr= ptr->next;     // 次の構造体のアドレス
    }
    return ptr;
}

usr ~/Project/test/teratail % 


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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/17 23:30

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

    キャンセル

  • 2019/02/18 00:28

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

    キャンセル

  • 2019/02/18 00:29

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

    キャンセル

  • 2019/02/18 05:39 編集

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

    キャンセル

  • 2019/02/18 09:23 編集

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

    キャンセル

  • 2019/02/18 10:35

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

    キャンセル

  • 2019/02/18 10:47 編集

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

    キャンセル

  • 2019/02/18 11:22

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

    キャンセル

  • 2019/02/18 12:44

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

    キャンセル

  • 2019/02/20 21:45

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

    キャンセル

0

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

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

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

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

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

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

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


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

// play : パーティリスト
// chara: 追加するメンバー名

void paty_ch(player_t *play, char *chara)
{
    player_t *newMember;
    player_t *lastMember = play;            // 最後のメンバー検索用
    newMember = malloc(sizeof(player_t));    // 追加メンバー用の領域確保
    strcpy(newMember->name, chara);            // 最後のメンバー名を設定
    // newMember->id = ??
    // newMember->level = ??
    // ... 以下、同様の他の変数はどうする??
    newMember->next = NULL;                // 最後のメンバーのポインタは、NULLとする。
    while (lastMember->next != NULL) {
        lastMember = lastMember->next;
    }
    lastMember->next = newMember;
    newMember->prev = lastMember;
}


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

参考として。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/16 20:15

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

    キャンセル

  • 2019/02/16 21:02

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

    キャンセル

  • 2019/02/17 05:12 編集

    参考までに、「もう一度基礎からC言語」 https://www.grapecity.com/developer/support/powernews/column/ 完読していませんが、かなり詳しいと思われるので。

    キャンセル

  • 2019/02/17 16:51

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

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/17 16:53

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

    キャンセル

0

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    4674questions

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