はじめての構造体とか

ロベールのC++教室 第1部68章くらいまでざざっと。

コンパイル時に色々教えてくれるの、割と性にあっているかもしれない。

  • 関数名は関数のアドレスを返す。
int main() {
    printf("%p", main);    // => 0x10a23eee0
}
  • 配列変数名は先頭の要素のアドレスを返す。
int array[] = {1, 2, 3, 4, 5};
printf("%p", array);        // => 0x7ffeeb482a80
printf("%p", &array[0]);    // => 0x7ffeeb482a80
  • アドレス[インデックス]*(アドレス+インデックス)は同じ。
int array[] = {10,20,30,40,50};
printf("%d\n", array[3]);      // => 40
printf("%d\n", *(array+3));    // => 40   
  • signedは符号付き、unsignedは符号なし
  • 接頭辞sz: string zero terminated

  • sizeof

    • sizeof 変数名でその変数のバイト数を返す
    • sizeof(型名)でその型のバイト数を返す
    • sizeof arrayでその配列全体のバイト数を返す
    • sizeof *arrayでその配列の最初の要素のバイト数を返す
    • よって、配列の要素数を求めたければsizeof array / sizeof *arrayとする。
    • size_of 演算子の返却値はsizeof_tという特殊な型であり、printfではunsigned longと同様%luを用いる。
    • 配列の要素数を求めるだけでこんなに面倒なのかとびっくりする。rubyならarray.sizeで済むのにな。
int array[] = {1, 2, 3, 4, 5};
printf("%lu\n", sizeof array);                    // => 20
printf("%lu\n", sizeof *array);                   // => 4
printf("%lu\n", sizeof array / sizeof *array);    // => 5
  • 値渡し/参照渡し
    • 基本的に関数に引数を渡すときは値渡しになる。
    • しかし配列は変数名の正体がポインタなので、ポインタを渡す(参照渡し)になる。
    • 構造体も原則値渡しになってしまうが、サイズがでかくなりがちな構造体をばんばん値渡ししてメモリ上のそこらじゅうにコピーをつくるのは嫌なので、以下のように参照渡しするのがベター。
struct SStudent {
    char szName[16];
    int nEnglish;
    int nMath;
    int nScience;
};

void Disp(SStudent& student) {              // この"&"で参照渡し
    printf("%s\n", student.szName);
    printf("%d\n", student.nMath);
}

int main() {
    SStudent students[] = {
        {"yamada", 67, 49, 84},             // 構造体の初期化子は"{ }"で囲む
        {"tanaka", 90, 65, 69}
    };
    for(int i=0; i<(sizeof students/sizeof *students); i++)
        Disp(students[i]);
}