はじめに: 今回の内容は、前号の「C言語基礎 関数編(前編)」の内容を引き継ぎ、関数の知識を解説していきます。
目次
1. 関数のネストされた呼び出しとチェーンアクセス
1. ネストされた呼び出し
関数は実際のニーズに応じて組み合わせることができます。つまり、関数を使用するときに、ネストされた callである関数本体内で別の関数を呼び出すことができます。
#include<stdio.h>
void fun1()
{
printf("hehe\n");
}
void fun2()
{
printf("haha\n");
fun1();
}
int main()
{
fun2();
return 0;
}
このような単純なコードを見てみましょう。関数 fun2 で関数 fun1 を呼び出し、次にmain 関数で関数 fun2を呼び出します。結果は次のようになります。
「へへ」と「はは」の両方が出力されます。これは、ネストされた呼び出しです。
ここで、関数はネストして呼び出すことはできますが、ネストして定義することはできない、つまり、1 つの関数内に別の関数を定義することはできないことに注意してください。
#include<stdio.h>
void fun2()
{
void fun1()
{
printf("hehe\n");
}
printf("haha\n");
}
int main()
{
fun2();
return 0;
}
上記のようなコードは絶対に許可されません。これは、main 関数内に関数を定義できないのと同じです。
2. チェーンアクセス
関数の戻り値 (関数末尾) を別の関数 (関数先頭) のパラメータとして使用し、関数チェーンのように複数の関数を最初から最後まで順番に接続すると理解できます。これがチェーン訪問です。
理解を助けるために一般的な例を見てみましょう。
#include<stdio.h>
#include<string.h>
int main()
{
int arr[] = "1234567";
int len = strlen(arr);
printf("%d", len);
return 0;
}
-------------------------------------------------------------------------------------------
int main()
{
int arr[] = "1234567";
printf("%d", strlen(arr));
return 0;
}
strlen() 関数とprintf() 関数はどちらも一般的に使用される関数です。まず最初のコード部分を見てみましょう。strlen () 関数の戻り値を受け取るために整数変数 len を定義し、その後len が使用されますprintf() 関数として引数が出力されます。
2 番目のコードをもう一度見てみると、 strlen() 関数の戻り値を受け取る変数を定義せず、strlen(arr) を printf() 関数のパラメータとして直接使用しています。
実際、strlen(arr) は strlen() 関数の対応する戻り値ですが、通常は受け取る新しい変数を定義するために使用されます。
2. 関数の宣言と定義
1. 関数宣言
- 関数の呼び出し内容、パラメータ、戻り値をコンパイラに伝えます。これが関数の宣言です。
- 関数の宣言は使用前に行われます。
#include<stdio.h>
int main()
{
int a = 2;
int b = 5;
Add(a, b);
return 0;
}
void Add(int x, int y)
{
printf("%d", x + y);
}
前回の説明で書いたコードではカスタム関数がメイン関数の前にありましたが、今回はメイン関数の後ろに置きましたが、違いはありますか?? ?
残念ながら、このアプローチは間違っています。
コンパイラはコードを上から下に 1 行ずつ読み取ることがわかります。上記のコードでは、Add 関数が main 関数の後にあるため、コンパイラが main 関数で Add 関数を呼び出すと、コンパイラはAdd 関数を認識しません。 functionなので、エラーが発生しただけです。
しかし、この場合、カスタム関数はメイン関数の後になければなりませんか? ? ? もちろん違います:
#include<stdio.h>
void Add(int x, int y);//提前声明
int main()
{
int a = 2;
int b = 5;
Add(a, b);
return 0;
}
void Add(int x, int y)
{
printf("%d", x + y);
}
add 関数を main 関数の前に宣言するだけで、通常どおり使用できます。ここでの宣言には関数のヘッダーのみが必要なので、コンパイラは Add 関数を覚えて、最後に';'を追加することを忘れないでください。
2. 関数の定義
関数がどのような構造になっており、何を行うのかを具体的に説明します。これが関数の定義です。
void Add(int x, int y)
{
printf("%d", x + y);
}
これは単純な加算関数の定義です。
3. 関数の再帰
1. 再帰とは何ですか
簡単に言うと、再帰は入れ子になって自分自身を呼び出す関数、つまり入れ子人形です。大きなものを小さなものに変えるというアイデアです。
史上最も単純な再帰コードを紹介します。
#include<stdio.h>
int main()
{
printf("hehe\n");
main();
return 0;
}
結果は次のとおりです。
「へへ」と延々と出力されます。
2. 再帰に必要な 2 つの条件
- 実は関数の再帰もループに似ていて制限があり、この制限に該当すると再帰は続行されなくなります。
- 再帰呼び出しが行われるたびに、この制限にどんどん近づいていきます。
関数の再帰を詳しく説明するために、正式に例を使用してみましょう。
整数値 (符号なし) を受け取り、その各ビットを順番に出力します。
例: 入力: 1234、出力: 1 2 3 4。
このコードを再帰せずに普通に書くと、最初に、ローリングと除算を使用して商を求めるだけで済みます。
#include<stdio.h>
int main()
{
int n;
scanf("%d", &n);
int count = 1;
int z = n;
while (z > 10)//循环统计位数
{
z /= 10;
count *= 10;
}
while (count > 0)//辗转相除取商
{
int x = n / count;
n = n % count;
count /= 10;
printf("%d ", x);
}
return 0;
}
普通に書くのは難しくないものの、コードが少々面倒であることがわかります。では、再帰はどのように実現されるのでしょうか。
#include<stdio.h>
int print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int n;
scanf("%d", &n);
print(n);
return 0;
}
この再帰的なコードがどのように機能するかを詳しく説明しましょう。
まず、整数「1234」を入力します。
関数では、n > 9 は制限です。
n > 9 の場合、関数を再帰的に呼び出し、n / 10 の商をパラメータとして渡します。
n == 1 になるまでネストを停止せず、n % 10 の残りを内側から外側に出力し始めます。
それでも理解できない場合は、次に何をするかを見てみましょう。
#include<stdio.h>
int print(int n)// n = 1234
{
if (n > 9)
{
int print(int n / 10) //n = 123
{
if (n > 9)
{
int print(int n/ 10)//n = 12
{
if (n > 9)
{
int print(int n / 10) //n = 1
{
if (n > 9)//不满足
{
print(n / 10);//不执行
}
printf("%d ", n % 10);//打印1
}
printf("%d ", n % 10);//打印2
}
printf("%d ", n % 10);//打印3
}
printf("%d ", n % 10);//打印4
}
この形になったら、悟りを開くでしょうか? ははは、はい、実際、本質はこの種の入れ子人形ですが、このようなコードは書けません。1つは冗長で、もう 1 つはコンパイラが実行できないためです。渡してください。
4. まとめ
関数の再帰はC言語の知識の重要なポイントであると同時に難しいポイントでもあるため、ブロガーはここではあまり説明しません。関数の再帰について詳しく説明する記事を時間を作って書きますので、楽しみにしていてください。!
さて、関数に関する知識はこれで終わりです。ブロガーの記事が好きな友達は、3 回クリックすることを忘れないでください。
次回お会いしましょう!