わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

ま,メンバを書こう

構造体の中身を出力するプログラム…

#include <stdio.h>

struct person {
  char name[20];
  int age;
};

void print_person(struct person *pp)
{
  printf("Name: %s\n", pp->name);
  printf("Age:  %d\n", pp->age);
}

int main(void)
{
  struct person p = {
    "takehikom",
    24
  };

  print_person(&p);

  return 0;
}

何の変哲もないプログラムですが,昨日の演習で見かけて驚いたこととして,Nameの出力を

  printf("Name: %s\n", pp);

と書いても,同じ出力になります.
少し考えてみれば,ここのppとpp->nameが同じアドレスになっていると想像できます.ただしアドレスは同じでも型は違うので,行儀のいい使い方とは言えません.実際,gcc -Wallでコンパイルすると,「警告: 初期化により、キャストなしでポインタから整数を作りました」という警告が出ました.
それと,nameが,構造体の中で先頭のメンバになっているのも,たまたま動く要因でして,これの順序を変えてから,「printf("Name: %s\n", pp);」とすると,何も出力しないとか,ゴミが出力されるとかいったことになります.上のプログラムで,nameとageの位置を交換する*1と,Nameには何も出ません.ageの初期値を,24から-1に変更すると,4バイトのゴミのあとに「takehikom」が出ました.リトルエンディアンだとか2の補数だとかを採用していることがうかがえます.
最後に,構造体を使ったプログラムを自在に書きたい人へのアドバイス:

  • 「.」と「->」は2項演算子ですが,これらの演算子については,前後に空白を置かないのが慣例です.
  • 構造体のポインタを引数にとる関数を書くとき,ポインタと分かる引数名にしましょう.構造体オブジェクトと同じ変数名にすると,混乱のもとです.
  • 構造体を自分で定義したら,次に,その中身を見る(標準出力に出す)関数を定義しましょう*2

*1:pの初期化も書き換える必要があります.

*2:http://d.hatena.ne.jp/takehikom/20070514/1179093182