ポインタのお話〜ポインタってどういう時に役に立つの?〜

【ポインタってどういう時に役に立つの?】

ポインタがあるということは、それが役に立つからあるのです。(^^;)
どういう時に役に立つのかというと、

  1. 呼び出した関数と値の受け渡しをするとき
  2. どれぐらいの要素数かわからない配列の変数を扱うとき

というのが代表例です。
理解の手助けのためには、まず【スコープって何?】の項目をちょっと先に読んでおいて下さい。
スコープが何かが分かる方は別に読まなくってもいいですよー。

【呼び出した関数と値の受け渡しをする】

呼び出した関数と値の受け渡しするときには、

  1. 関数の引数で値を渡し、計算結果を関数の戻り値として受け取る
  2. 関数の引数でアドレス値を渡し、関数側ではポインタ変数としてアドレス値を受け取る計算結果を関数側でポインタ変数に代入する

の2つのパターンが考えられます。

グローバル変数に値をほうり込むというのはこの場合無視しますね。

1の場合は、計算結果として返したい値が一つだけのときには使えますが、複数ある場合には使えない方法です。
こういう場合には、2の方法を取り入れます。

例えば、ある値(inData)を入れると、その計算結果を返してくれる関数を作ったとします。
普通なら、

  outData = funkKeisan(inData);

でよさそうなんですが、呼び出している関数の途中で何らかのトラブルが発生してエラーを返してしまう場合がありえるのでしたら、

  error_check = funkKeisan(inData, &outData);

のような使い方をするのが賢いといえるでしょう。

-------------------------------------------
2)のパターンの例
# 図で使っている器の大きさは気にしないでね…。

 void funkA(){
   int iData;
    :
   funkB(&iData); /* step 1. 3. */
    :
 }

 int funkB(int *iData){ /* step 1. */
    :
   /* 何らかの計算をし、その値をiDataに代入 step 2. */
 }

[step 1.] funkAのiDataのアドレス値を引数としてfunkBを呼び出す。
この時、funkAのiDataのアドレス値はfunkBのiDataにコピーされる。
funkB では iDataには funkAでのiDataのアドレス値が入っている。
*iDataで funkAでのiDataの値を参照できる。
funkAで使っているiDataを器ごとfunkBに貸し出している形になる。

  funkA            funkB
  iData ││ ─→ *iData ┃┃
        └┘  貸出       ┗┛

[step 2.] funkB内部で計算を行う。その結果を*iDataに代入する。

  funkA           funkB
  iData ││      *iData ┃┃←→(計算)
        └┘             ┗┛

[step 3.] funkAにiDataの器を返却する。(語弊はあるけど…) funkAのiDataの内容は、funkBで計算された結果になっている。 この時点で、funkBのiDataは破棄される。

  funkA           funkB
  iData ┃┃ ←─ *iData ││
        ┗┛  返却       └┘

-------------------------------------------

【どれぐらいの要素数かわからない配列の変数を扱うとき】

ポインタ型または配列のデータを扱いたいのだけれども、そのままでは使いにくいという場合、本当は配列のデータとして扱いたいのだけれども、どうしてもそういう訳にはいかない場合にはこんな方法はいかがでしょうか。

例1:ポインタ型または配列のデータを扱いたいのだけれども

  char pcData[65536];
  char *pcBuffer;

  /* : */
  /* 値をもらう処理が入る */
  funk_GetData(pcData);
  /* : */
  /* 有効な要素の数値を4分の1している */
  for(pcBuffer=pcData; *pcBuffer!=0; pcBuffer++)
   *pcBuffer >>= 2;

となります。また、

  char pcData[65536];
  int cnt;

  /* : */
  /* 値をもらう処理が入る */
  funk_GetData(pcData);
  /* : */
  /* 有効な要素の数値を4分の1している */
  for(cnt=0; pcData[cnt]!=0; cnt++)
   pcData[cnt] >> 2;

としても同じ事ですので、好みと用途に合わせてお使いになればいいと思います。

例2:本当は配列のデータとして扱いたいんだけれども
# 皆さん、構造体はわかるかな…?

 typedef struct _AddressData {
   char FirstName[50];
   char FamilyName[50];
   struct _BirthDay {
    int year;
    int month;
    int day;
   } BIRTHDAY BirthDay;
   char Address[256];
   char JipCode[10];
   char PhoneNo[15];
   char Email[50];
 } ADDRESS_DATA;

 fnk_GetAddressData(){
   ADDRESS_DATA *pAddresData; /* アドレス帳データ */
   int iMembers; /* アドレス帳に登録されている人数 */

   /* アドレス帳に何人の人が登録されているか */
   iMembers = GetMembers();

   /* 人数分のデータの領域を確保 */
   pAddressData = (ADDRESS_DATA*)malloc(sizeof(ADDRES_DATA)*iMembers);
    :
    :
   /* データとして確保した領域を開放 */
   free(pAddressData);
 }