わさっきhb

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

関数を教える際の注意点

  • 仮引数には,直前に型名を書いておかないといけません.実引数には,型名を書いてはいけません.
  • 呼び出す側と,呼び出される関数とで,引数の数を一致させます.
    • ただし,printfやscanfは例外です.この例外を学ぶには,可変個数の実引数とか,動的関数といった概念,あるいはstdarg.hを理解するといいでしょう.とはいえ,初学者の学ぶべき範囲を超えているし,自分でそんな関数を定義することはめったにありません.
  • 実引数と仮引数の型を一致させます.複数あればその順番に.戻り値と,呼び出し元で使用するところも,型を一致させます.
    • ただし実際には,少々型が違っていても,代入できればよいと言えます.その際,型変換に注意します.
#include <stdio.h>

int half(int value)  // intに注意.gcc -Wallでも警告されません.
{
  double h = value;
  return h / 2;
}

int main()
{
  double h = 1;
  h = half(h);  // 0.5ではなく0が代入されます.
  printf("%f\n", h);
  return 0;
}
  • 「参照渡し」をどう教えるか…現在の結論は次の通りです.
    • Cでの関数の引数の授受は,「値渡し」です.なので,関数内で仮引数の値を変更しても,呼び出し元の実引数には影響を及ぼしません.
    • プログラミング言語によっては,「参照渡し」というのがあります.これを使えば,関数内で,実引数の値を変更することができます.Cでは,ポインタ渡し(アドレス渡し)を用いて,関数内で仮引数の参照先に代入することにより,実現できます.
  • 関数は「自分で定義する」だけでなく,「既存のもの(標準ライブラリ関数)を呼び出す」ことも多いです.API (Application Programming Interface)と呼ばれる概念とも関連します.
  • 仮引数と,関数内のauto変数は,関数呼び出しごとに,メモリの中のスタックと呼ばれる領域に確保されます.関数処理が終わると,破棄されます.
    • aが関数内のauto変数のとき,「return &a;」のようにその変数を指すポインタを返すよう書くことはできますが,呼び出し元でその変数の値,すなわち関数内のローカル変数を使用してはいけません.
    • aが関数内のstatic変数のときは,「return &a;」と書いて利用してもよいのですが,再入可能(リエントラント)でない関数となります.
  • 構造体に対する処理を関数として定義するとき,第1引数にそのポインタをとるように書きます.多くのAPIでこの書き方を採用しているし,この書き方に慣れると,オブジェクト指向言語を学ぶ際,メソッド呼び出しの書き方へ,スムーズに移行できます.

(追記)

  • 仮引数に配列の形式で型を書いても,その仮引数はポインタ変数です.実引数が配列であっても,sizeof(仮引数)で配列のバイト数は求められません.