BONO's pageプログラム覚書

関数に関するメモ [2004年6月]

- 関数の引数は値渡し
  • C/C++言語では,関数の引数は値渡し方式になっている.
    • 例えば,int型変数xに10という値が格納されているとき,関数の引数として変数xを指定した場合は,呼び出した関数へは変数xが渡されるのではなく,変数xの値10が渡される.
    • よって,指定した変数の内容は,呼び出した関数内で変更することができない
    • 他の言語(BASIC言語など)では,関数の引数が参照渡し方式になっているものがある.
    • CやC++言語で,引数で渡した変数の内容を,呼び出した関数内で変更したい場合は,引数として,その辺数のアドレス値を渡すようにする.そして,呼び出される関数では,そのアドレス値を,ポインタ変数で受け取るようにする.
    • プログラム例
       void func ( int * p ) ;
         {
             *p += 10 ;
        }

        int main ( )
        {
            int x = 5 ;

            func ( &x ) ;

            printf ( "x= %d\n ", x );
        } 
  • C++言語では,引数を「参照渡し方式」とすることも可能.
    • 「参照渡し方式」だと,引数で渡した変数の内容を,呼び出した関数内で変更することが可能となる.
    • プログラム例
       void func ( int & x ) ;
         {
             x += 10 ;
        }

        int main ( )
        {
            int x = 5 ;

            func ( x ) ;

            printf ( "x= %d\n ", x );
        } 

- 関数に配列を渡す場合
  • このときの関数のプロトタイプ宣言は
       戻り値のデータ型 関数名(データ型 配列名[]);
  • のように記述する.[ ] の中に配列のよう素数を記述する必要はない.
  • 関数に配列を渡すときは,
       dispArray(a);
  • のように配列名だけを記述する.また,配列を受け取る関数側はのように記述すると,その変数のアドレスを取得することができる.
       int dispArray(int dat[])
  •  のように[]が必要となる.
  • また,関数は受け取った配列の要素数を調べることができない.
  • したがって,関数内で配列要素を参照する場合,以下のようにする.
  • プログラム例
     #include <stdio.h>

     #define NUM 5 /* 要素数 */

     /* 関数のプロトタイプ宣言 */
     int dispArray(int dat[]);

     /* main関数 */
     int main(void)
     {
         int a[NUM]={1,2,3,4,5};

      /* 関数呼び出し */
      dispArray(a);

      return 0;

    }

     /* dispArray関数 */
     int dispArray(int dat[])
     {
       int i;

       for(i=0;i<NUM;i++)
       {
         printf("dat[%d] %d\n",i,dat[i]);
       }
     return 0;
     }
  • 関数に渡されているのは,配列の先頭アドレスである.よって,配列aの先頭アドレスが,関数に渡され,関数側で使う配列datの先頭アドレスにしている.なので,配列aと配列datは,メモリ上で同じ領域を参照している.
  • 引数の引き渡しには,値渡しと参照渡しがある.C言語では,特別なことをしない限り,変数は値渡し,配列は参照渡しになる
  • 値渡し
    • 関数に変数を渡したときは,その変数のコピーが渡される.関数が受け取った引数は,メモリ上の別の領域を使う.そのため,引数の値を更新しても,もとも関数には影響しない.
  • 参照渡し
    •  配列の場合は,先頭アドレスが関数に渡される.呼び出し元と受け取った側とで別の名前を使っていても,メモリ上の同じ領域を参照している.そのため関数で配列の内容を変更すると,呼び出し元の値も更新される.

- 配列を渡す方法
  • 関数には配列の先頭アドレスが渡される.受け取った側の関数では,要素数を知ることができない.そのため,要素数を別の変数で渡すなどの工夫が必要となる.
その1:要素数を別に渡す
サンプルコード
 int dat[]={60,72,85,93,42,33};
 int n;

 n=sizeof(dat)/sizeof(int);

 ans=average(dat,n);

 float average(int dat[],int n)
 {
   int i;
   int total=0;
   float ans;

   for(i=0;i<n;i++)
   {
     total=total+dat[i];
   }

   ans=(float)total/(float)n;

   return ans;

 }

その2:ありえない値を配列の終端にする
サンプルコード
 int dat[]={60,72,85,93,42,33,-999};

 ans=average(dat);

 float average(int dat[])
 {
   int i=0;
   int total=0;
   float ans;

   while(dat[i]!=-999)
   {
     total=total+dat[i];
     i=i+1;
   }

   ans=(float)total/(float)i;

   return ans;

 }

- 二次元配列の受け渡し
  • 一次元配列同様,関数には
       関数名(配列名);
  • という書式で渡す.
    このとき関数に渡されるのは,二次元配列の先頭アドレスである.ただし,先頭アドレスを受け取った関数側では,その配列の構造を正しく定義しなければならない.
サンプルコード
 #include <stdio.h>

 int dispData(int dat[][10]);

 int main(void)
 {
   int a[2][10]={{1,2,3,4,5,6,7,8,9,10},
                   {11,12,13,14,15,16,17,18,19,20}  };

   dispData(a);

   return 0;

 }

 int dispData(int dat[][10])
 {
   int i;
   int j;

   for(i=0;i<2;i++)
   {
     for(j=0;j<10;j++)
     {
       printf("%2d ",dat[i][j]);
     }
     printf("\n");
   }
   return 0;
 }
このように受け取った関数側で列数を定義する必要がある.

戻り値のデータ型 関数名(データ型 配列名[][列数]);



[前画面に戻る]

Copyright(C)1998 Shinichi Takeshita.All Rights Reserved.