C言語の関数
導入
C 言語では通常、次の 2 種類の関数が見られます。ライブラリ関数そしてカスタム機能
以下にこれら 2 つの機能を紹介します。
ライブラリ関数
では、ライブラリ関数とは何でしょうか? C 言語の国際標準である ANSI C では、標準ライブラリと呼ばれる一般的に使用される関数の標準が規定されており、ANSI が定めた C 言語標準に基づいて各コンパイラメーカーから一連の関数実装が提供されています。これらの関数はライブラリ関数と呼ばれます。
つまり、私たちが使っているコンパイラに付属している関数のことで、例えば私たちが普段使っているものはすべてライブラリ関数printf
です。scanf
しかし、私たちが注意しなければならないことが一つあります。これらのライブラリ関数を使用する場合は、対応するヘッダー ファイルを引用する必要があります。例: #include<stdio.h>
。
ライブラリ関数の使い方とライブラリ関数の学習方法
ここでは 2 つの非常に便利なツールをお勧めします。1
. c/c++ 公式リンク:リンク
2. cplusplus.com.
赤いボックスでは、見つけたい関数を検索できます。青いボックスでは、いくつかの関数が表示されます。一般的なヘッダー ファイルをクリックすると、それらに含まれる関数が表示されます。
関数をsqrt()
例に、その関数のパラメータと戻り値の型を紹介し、例も示してくれて、かなり充実していると言えます。
カスタム機能
関数パラメータと実パラメータ
実パラメータは、関数に実際に渡されるパラメータです。
仮パラメータはメモリ内のスペースには適用されず、実際には存在しません。。仮パラメータは、関数が呼び出されたときに実際のパラメータによって渡される値を保存するためのメモリ内のスペースにのみ適用されます。このプロセスはフォームのインスタンス化です。
それで、両者の関係は何でしょうか?コードを見てみましょう
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0, b = 0;
scanf("%d%d", &a, &b);
int ret = Add(a, b);//加法函数,ret接收返回值
printf("%d\n", ret);
return 0;
}
操作結果は以下の通りです。&a
監視ウィンドウで、&b
、 、&x
の&y
アドレスをそれぞれ見てみるのはどうでしょうか。
デバッグ中に、x と y が a と b の値を取得したことが観察できますが、x と y のアドレスは a と b のアドレスとは異なるため、== 仮パラメータは実際のパラメータ の一時コピー。==また、仮パラメータを変更しても実際のパラメータには影響しません。
関数のパラメータとしての配列
ここでは、配列に渡されるいくつかのパラメータを知る必要があります。重要な知識:
• 関数の仮パラメータは、関数の実パラメータの数と一致する必要があります。
• 関数の実パラメータは配列であり、仮パラメータは配列形式で記述することもできます
。 • 仮パラメータが 1 次元配列の場合、配列サイズは省略可能
• 仮引数が次の場合 2次元配列の場合、行は省略できますが、列は省略できません
配列で引数を渡す場合、仮引数は新しい配列を作成しません
仮引数の配列演算と実パラメータの配列は同じ配列です。
これら 2 つのコードを比較すると、コード 1 で計算された配列の長さが間違っていることが明らかですが、これはなぜでしょうか? 注意深く分析してみましょう:
写真で丸で囲んだ場所を見て、この時点で渡された値が同じでarr
ある&arr[0]
ことがわかります。配列がパラメータとして関数に渡される場合、配列の最初の要素のアドレスが渡されます。
ネストされた呼び出しと関数の連鎖アクセス
ネストされた呼び出し
ネストされた呼び出しは、名前が示すように、関数間の相互呼び出しです。ここでは例としてコードを取り上げます。
int is_leap_year(int y)
{
if(((y%4==0)&&(y%100!=0))||(y%400==0))
return 1;
else
return 0;
}
int get_days_of_month(int y, int m)
{
int days[] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int day = days[m];
if (is_leap_year(y) && m == 2)
day += 1;
return day;
}
int main()
{
int y = 0;
int m = 0;
scanf("%d %d", &y, &m);
int d = get_days_of_month(y, m);
printf("%d\n", d);
return 0;
}
関数内で関数を呼び出します。この関数には、閏年かどうかを判断するためのネストされた呼び出しがあります。main()
これが関数のネストされた呼び出しです。将来、関数を記述するときに、ネストされた関数の呼び出しを頻繁に使用することになります。いくつかの大規模なプロジェクト。get_days_of_month()
is_leap_year()
連鎖アクセス
いわゆるチェーンアクセスとは、ある関数の戻り値を別の関数のパラメータとして利用することであり、関数をチェーンのように繋ぐことを関数のチェーンアクセスといいます。
コードに直接移動します。
int main()
{
printf("%d\n",strlen("abcdef"));//链式访问
return 0;
}
strlen()
ここでは、関数の戻り値を関数パラメータとして直接与えますprintf()
。
関数の宣言と定義
単一ファイル
ただ 1 つだけ覚えておいてください。使用前に宣言する
加えて関数の定義も特別な宣言であるため、関数の定義を呼び出しの前に配置しても問題ありません。
複数のファイル
コード量が多い場合は、すべてのコードを 1 つのファイルにまとめるのではなく、プログラムの機能に応じて複数のファイルに分割することがよくあります。
一般に、関数宣言と型宣言はヘッダー ファイル (.h) に配置され、関数の実装はソース ファイル (.c) ファイルに配置されます。関数を例に
挙げてみましょう: add.cAdd()
//函数的定义
int Add(int x,int y)
{
return x+y;
}
追加.h
//函数的声明
int Add(int x,int y);
test.c
int main()
{
int a=10, b=20;
//函数调用
int ret=Add(a,b);
printf("和为%d\n",ret);
return0;
}
実行結果:
複数のファイルにコードを記述すると、宣言と定義を明確に区別できるため、関数の実装をよりよく観察できるようになり、コードの可読性が大幅に向上します。