カテゴリー
コンピューター

【C言語】メンバがポインタの構造体の扱い方【Windows】【RHEL7】【gcc】

C のコードに触れさせていただきました。

ポインタの理解もままならぬ中、次のようなことをおぼろげながら掴みましたの!

C 言語では関数へは値渡しのみしか存在しない。そして、関数へ多くの値渡しを行うと、パフォーマンスが劣化する。

そこで、変数や構造体のアドレス情報であるポインタを値渡しし、ポインタから変数の値へとアクセスして更新することでパフォーマンスを保つ。

以上のことを活かすために、メンバがポインタの構造体を関数へと渡せばパフォーマンスを落とさずにコードの見通しを良く保てるはず、と考えました。

しかしながら、これに躓きましたの><。

ポインタ構造体への、代入、取り出し、関数への渡し方、これらを行いたいだけですのに!

そして、ポインタ構造体を関数の引数にして、関数内部でポインタ構造体のメンバの値を変更したいですの!

学習してていく中で、

のページが理解に非常に役立ちました。

今回は、現在のわたくしたちの理解をメモ書きしていきたいと存じます!

ポインタ構造体を使った C 言語のサンプルコード

  • ポインタ構造体は、malloc 関数で初期化した。これを行わないと、Windows では問題は置きなかったが、RHEL7 で実行時エラーとなった。
    [構造体の文字列 初期化] などで調べ、次のページが役立った。
    【C言語】構造体の定義と初期化【豆知識いろいろ】 | MaryCore
  • 文字列は char の配列なため(だと思う)、配列ではない変数と扱いが異なる。難しい。
  • ポインタ構造体のメンバ変数と他の変数を結びつける例: c->id = &a.id;
  • ポインタ構造体のメンバ配列(文字列)と他の配列(文字列)を結びつける例: c->name = b.name;
  • ポインタ構造体のメンバ変数を通してポイント先の他の変数の値を変更する例: *c->id = 33333;
  • ポインタ構造体のメンバ配列(文字列)を通してポイント先の他の配列(文字列)の値を変更する例: strcpy(c->name, "ccccc");
#include <stdio.h>
#include <string.h>

// ポインタ構造体にポイントされる構造体その 1
typedef struct {
    int id;
    char name[9];
} StructureA;

// ポインタ構造体にポイントされる構造体その 2
typedef struct {
    int id;
    char name[9];
} StructureB;

// ポインタで構成された構造体
typedef struct {
    // ポインタ
    int id;
    char name[9];
    // 通常の変数
    char value[9];
} StructureC;

// ポインタ構造体のポイント先の値等を更新する関数
void update(StructureC *c) {
    // 構造体の int 要素をポインタを指定して変数値を変更
    // ポインタ (c->id) の、値 (*) に代入することで、ポイント先の変数値を更新
    *c->id = 33333;
    // 構造体の char 要素をポインタを指定して変数値を変更
    // strcpy 関数を使って、c->name ポインタの指す格納先に、指定文字列をコピー
    strcpy(c->name, "ccccc");
    // 通常の変数である char の構造体の要素の値を変更するには、
    // 同様に、strcpy を使って、c->value ポインタ先の格納先に、指定文字列をコピー
    // 本関数には StructureC のアドレスのみが渡ってきているため、
    // strcpy(c.value, "second"); というように値を変更することはできず、
    // コンパイルエラーとなる。
    strcpy(c->value, "second");
}

int main(void) {
    StructureA a;
    memset(&a, 0x00, sizeof(StructureA);
    a.id = 11;
    strcpy(a.name, "aaa");

    StructureB b;
    memset(&b, 0x00, sizeof(StructureB);
    b.id = 22;
    strcpy(b.name, "bbb");

    // 構造体ポインタの初期化
    StructureC *c = malloc(sizeof(*c));
    // 構造体の int ポインタと変数を結びつける
    c->id = &a.id;
    // 構造体の char ポインタと変数を結びつける
    c->name = b.name;
    // 構造体の char 変数に代入
    strcpy(c->value, "first");

    // 関数の中で構造体の要素の値を更新
    update(C);
    // malloc で確保した場合はメモリブロックを必ず解放
    free(c);

    // 結果を確認
    // StructureA.id は StructureC->id にポイントされている。
    // よって、StructureC->id のポイント先の値の変更を行うと、
    // StructureA.id の値が変更される。
    printf("StructureA.id: %d¥n", a.id);
    printf("StructureA.name: %s¥n", a.name);
    printf("¥n");
    printf("StructureB.id: %d¥n", b.id);
    // StructureB.name は StructureC->name にポイントされている。
    // よって、StructureC->name のポイント先の値の変更を行うと、
    // StructureB.name の値が変更される。
    printf("StructureB.name: %s¥n", b.name);
    printf("¥n");
    // ポインタ構造体のメンバの値を取り出すには、
    // int ならば *c->id
    // char ならば c->name
    // ※文字列は char 配列なため、このような違いが生じるのだと思う。
    printf("StructureC->id: %d¥n", *c->id);
    printf("StructureC->name: %s¥n", c->name);
    printf("StructureC.value: %s¥n", c.value);
    printf("¥n");

    return 0;
}

おわりに

インターネットの情報の他に、次の書籍も非常に参考になりました♪

以上です。

コメントを残す