param2.cpp

/*
  仮引数の値を変更してみる
  (仮引数がポインタの場合)
  param2.cpp
*/

#include <stdio.h>

void f1( int * a ) {
  *a = 10;
  printf( "*a is %d\n", *a );
}

int main( void ) {

  int i = 100;
  f1( &i );
  printf( "i is %d\n", i );

  getchar( );
  return 0;
}


課題

/*
  int型の2つの変数の値を交換するmyswap関数を完成させよ。main関数の局所変数iとjの初期値が何であっても両者の値が入れ替わるようにmyswap関数を定義すること。
  myswap.cpp
*/

#include <stdio.h>

void myswap( -----ここを完成させる------ ) {
  ここを完成させる
}

int main( void ) {

  int i = 5, j = 10;
  myswap( &i, &j );
  printf( "i is %d\n", i ); /* i is 10 と表示される */
  printf( "j is %d\n", j ); /* j is 5  と表示される */  

  getchar( );
  return 0;
}
正解例
#include <stdio.h>

void myswap( int * p1, int * p2 ) {
    int t;
    t = *p1; *p1 = *p2; *p2 = t;
}

int main(void) {

    int i = 5, j = 10;
    myswap(&i, &j);
    printf("i is %d\n", i); /* i is 10 と表示される */
    printf("j is %d\n", j); /* j is 5  と表示される */

    getchar();
    return 0;
}


なお,このように仮引数にポインタを使う引数の渡し方を『アドレス渡し』と呼ぶ。
アドレス渡しの持つメリットは,他にも 大きいデータを関数に渡す場合に,サイズが大きい
データそのもの引数にするより,ポインタだけを渡した方が,値のコピーにかかる時間が
少なくて済むというてっが挙げられる。


■ポインタで参照している対象を保護(内容を変更されないように)するには

 ポインタで参照する対象(T型変数)を定数に指定して保護するには,const をつけたポインタ型

     const T *

で参照してやれば良い(下図)。なお,ポインタ変数自体をconst定数にするには,ポインタ変数を

      T * const

型で宣言すれば良い(下図)。




■引数の保護

 仮引数の宣言を const T * 仮引数 とすると,仮引数のポインタで指し示している対象の値
 を変更できなくなる
。 たとえば, void f( const int * p ) { *p = 10; } とすると青字部分が
 コンパイルエラーになる。

 ポインタ仮引数を使う関数では,

  ・ポインタ引数が指している変数(T型)を変更しない場合は,ポインタ仮引数は const T * 仮引数 とする。
  ・ポインタ引数が指している変数(T型)を変更する場合は,単に T * 仮引数 ポインタ仮引数は とする。

 ことで,利用者からは

  ・前者は,そのポインタ引数経由で値を返すことはない。
  ・後者は,そのポインタ引数経由で値を返す。

  という,「その間数の使い方」が明白になる。 また,

  ・前者は, const T * 仮引数 へは, const T *型の値も T * 型の値も渡せる。これは,T * 型→ const T *型への変換は安全だから許されているからである。
  ・後者は, T * 仮引数 へは, T * 型の値は渡すことができるが, const T *型の値は渡せない。これは, const T *型→ T*型への変換はconst性(定数性)が失われ危険なので禁じられているからである。

  という違いも出てくる(下図)。

pointerarg.cpp



■配列をポインタ仮引数で受け取る

 C言語では,配列をポインタ仮引数で受け取ることが多い。




■文字列引数

 以前学習したように,C言語では文字列は char型の配列 で表現されている。そして,項目4
 で学習したように,配列は先頭要素へのポインタとして取り扱われる。このため,文字列の
 仮引数は,const char * または char * として表現されることが多い。

 もちろん, 文字列仮引数は,
  ・実引数の文字列内容を変更しない場合は const char * とし,
  ・実引数の文字列内容を変更する場合は char * とする
 必要がある。

 なお,二重引用符で囲む文字列リテラル定数 ( "東京情報大学" や "こんにちは" )などは,定数
 なので,データ型としては const char * である。そのため,文字列リテラル定数を受け取る
 ための仮引数は, const char * 型とする必要がある。

 stringarg.cpp