C/C++ · 6 min read · Oct 09, 2025
C/C++を段階的に学ぶ - ページ 6
06. 段階的C/C++ — Cプログラミング - 関数
関数
| I. はじめに | |
| II. 関数の定義 | |
| III. 関数の種類 | |
| IV. 組み込み関数 |
| | 1. 数値関数
- 文字列関数
- 文字テスト関数 | | | V. ユーザー定義関数 | | | 1. 単純関数
- 引数付き関数
- 戻り値付き関数
- 再帰関数 | | | VI. ポインタと関数 | | | 1. 参照によるパラメータ渡し
- 値による呼び出し
- 参照による呼び出し | | | VII. ローカルとグローバル | | | VIII. ストレージクラス指定子 | | | 自動ストレージクラス
レジスタストレージクラス
静的ストレージクラス
外部ストレージクラス |
I. はじめに
ここでは、関数を使用した方法と使用しない方法の両方で、人物の住所を2回印刷するプログラムを示します。これは、関数の利点を示します。
| | #include
int main()
{
printf(“\n人物の名前”);
printf(“\n通り、アパート//家番号”);
printf(“\n郵便番号、都市”);
printf(“\n国”);
printf(“\n人物の名前”);
printf(“\n通り、アパート//家番号”);
printf(“\n郵便番号、都市”);
printf(“\n国”);
return 0;
} | #include
void address()
{
printf(“\n人物の名前”);
printf(“\n通り、アパート//家番号”);
printf(“\n郵便番号、都市”);
printf(“\n国”);
}
int main()
{
address();
address();
return 0;
} |
II. 関数の定義
値を引数として受け取り、呼び出しプログラムに結果を返す能力を持つステートメントブロックです。したがって、関数は特定のタスクを実行する自己完結型のステートメントブロックです。
III. 関数の種類
| | - 組み込み関数/ライブラリ関数/事前定義関数
- ユーザー定義関数 |
IV. ライブラリ関数
ライブラリ関数は、ソフトウェアの製造元によって設計され、ソフトウェアがロードされるときにディスクにロードされます。
以下の関数は、ライブラリ関数の例です。
1. 数値関数
| 関数 | 構文 | 例 | 結果 |
| Abs | Abs(n) | abs(-35) | 35 |
| ceil | ceil(n) | ceil(45.232) | 46 |
| floor | floor(n) | floor(45.232) | 45 |
| fmod | fmod(n,m) | fmod(5,2) | 1 |
| cos | cos(n) | cos(60) | 0.5 |
| sin | sin(n) | sin(60) | 0.866 |
| tan | tan(n) | tan(60) | 1.732 |
| sqrt | sqrt(n) | sqrt(25) | 5 |
| pow | pow(n,m) | pow(2,3) | 8 |
2. 文字列関数
| 関数 | 構文 | 例 |
| strlen | strlen(str) | strlen(“コンピュータ”) |
| strcpy | strcpy(target,source) | strcpy(res,”Pass”) |
| strcat | strcat(target,source) | strcat(“mag”,”gic”) |
| strcmp | strcmp(str1,str2) | strcmp(“abc”,”Abc”) |
| strrev | strrev(target,scr) | fstrrev(res,”LIRIL”) |
3. 文字テスト関数
| 関数 | 説明 |
| isalnum | 文字または数字である |
| isalpha | 文字である |
| isdigit | 数字である |
| iscntrl | 通常の制御文字である |
| isascii | 有効なASCII文字である |
| islower | 小文字である |
| isupper | 大文字である |
| isspace | 空白文字である |
| isxdigit | 16進数文字である |
利用可能な関数のライブラリは膨大であり、ここではその一部を示しました。より多くのライブラリ関数については、ヘルプマニュアルを参照してください。
V. ユーザー定義関数
すでに見たプログラムは、労働の分担を実行します。gets、puts、またはstrcmpを呼び出すとき、これらの関数の内部がどのように機能するかを心配する必要はありません。
これらと約400の他の関数は、Turbo Cライブラリで既に定義され、コンパイルされています。これらを使用するには、プログラムに適切なヘッダーファイルを含めるだけで済みます。「ランタイムライブラリ」のライブラリリファレンスで、関数を呼び出す方法と、返される値(ある場合)を理解してください。
しかし、自分の関数を書く必要があります。そのためには、コードを個別のセクション(関数)に分割する必要があります。それぞれが単一の、理解可能なタスクを実行します。関数は、Cライブラリ関数を呼び出すのと同じ方法でプログラム全体で呼び出すことができます。
関数を実装する手順
| | 1. 宣言
- 関数呼び出し
- 定義 |
| | • すべての関数はプログラムの最初に宣言されなければなりません。
• 関数定義には、実行タスクの実際のコードが含まれています。
• プログラムの最初に関数が定義されている場合、関数宣言は必要ありません。 |
実装を示す例関数
| | / 32_egfun.c /
#include
void address(); / 宣言 /
int main()
{
address(); / 関数呼び出し /
address(); / 関数呼び出し /
return 0;
}
void address() / 定義 /
{
printf(“\n人物の名前”);
printf(“\n通り、アパート//家番号”);
printf(“\n郵便番号、都市”);
printf(“\n国”);
} |
ユーザー定義関数は、呼び出し方に基づいて4つのタイプに分けることができます。
| | 1. 単純関数
- 引数付き関数
- 戻り値付き関数
- 再帰関数 |
1. 単純関数
特定のタスクのみを実行し、引数や戻り値は必要ありません。
単純関数の例
| | / 33_line.c /
#include
void line(); / 宣言 /
int main()
{
line(); / 関数呼び出し /
return 0;
}
void line() / 定義 /
{
int i;
for(i =1;i<80; i++)
putch(‘*’);
} |
2. 引数付き関数
引数を受け取る関数は、引数付き関数と呼ばれます。
例
| | / 34_argu.c /
void line(char ch, int n)
int main()
{
line(“-“, 50);
line(“*”, 8);
return 0;
}
void line(char ch, int n)
{
int i;
for( i = 1; i<=n; i++ )
putch(ch);
} |
3. 戻り値付き関数
呼び出しプログラムに値を返すことができる関数は、戻り値付き関数と呼ばれます。
例
| | / 35_retu.c /
int abs(int n);
int main()
{
int res;
printf(“%d”, abs(-35))
res = abs(-34); / 関数呼び出し/
printf(“%d”, res);
return 0;
}
void abs(int n)
{
if( n < 0 )
n = n * -1;
return n;
} |
4. 再帰関数
関数の本体内で同じ関数を呼び出すステートメントは「再帰」と呼ばれます。時には「循環定義」と呼ばれ、再帰は自己に関して何かを定義するプロセスです。
再帰関数の例
| | / 次のプログラムは自己呼び出しの関数を示します /
int main( )
{
printf(“\nこんにちは”);
main( ); / 自分自身を呼び出す関数 /
return 0;
} 実行しないでください。このプログラムはまだ説明であり、論理的に無効です。
同じ出力は別の関数を使用して達成できます: void disp( );
int main( )
{
disp( );
return 0;
}
void disp( )
{
printf(“\nこんにちは”);
disp( );
} |
プログラムは特定のポイントで終了する必要があるため、再帰の鍵は条件文を使用して定義できるソフトウェア割り込みにあります。
次の例を確認してください:
| | / 36_recursion.c /
int i = 1; / グローバル変数の宣言 /
void disp( );
int main( )
{
disp( );
return 0;
}
void disp( )
{
printf(“\nこんにちは %d “, i);
i ++;
if( i < 10 ) / iの値が10未満の場合、関数を再度呼び出す /
disp( );
} |
| | 与えられた数の階乗を求めるプログラム:
/ 37_fact.c /
int factorial(int x);
void main
{
int a, fact;
printf(“\n任意の数を入力してください “); scanf(“%d”, &a);
fact = factorial(a);
printf(“\n階乗は = %d”, fact);
}
int factorial(int x)
{
int f = 1, i;
for( i = x; i>=1; i–)
f = f i;
return f;
} | 再帰を使用して与えられた数の階乗を求める
/ 38_fact.c /
int rec_fact(int x);
int main( )
{
int a, fact;
printf(“\n任意の数を入力してください “); canf(“%d”, &a);
fact = rec_fact(a);
printf(“\n階乗の値は = %d”, fact);
return 0;
}
int f = 1;
int rec_fact(int x)
{
if( x > 1)
f = x rec_fact(x-1);
return f;
} |
VI. ポインタと関数
| | 参照によるパラメータ渡し
値による呼び出し
参照による呼び出し |
1. 参照によるパラメータ渡し
ポインタは関数宣言で使用でき、これにより複雑な関数を簡単に表現およびアクセスできます。関数定義は、2つの方法でポインタを使用します。
| | – 値による呼び出し
- 参照による呼び出し |
参照による呼び出しメカニズムは、値による呼び出しメカニズムよりも高速です。なぜなら、参照による呼び出しではアドレスが渡され、アドレスとの操作は通常の変数よりも速いためです。さらに、実際のパラメータごとに1つのメモリ位置しか作成されません。
プログラムの一部、実際の引数が関数を呼び出し、関数内で変更された値は、変更された形で呼び出しプログラムの呼び出し部分に返されます。これは参照による呼び出しまたはアドレスによる呼び出しと呼ばれます。このメカニズムで関数引数としてポインタを使用すると、データオブジェクトをグローバルに変更できます。つまり、関数内およびプログラムの呼び出し部分内で変更できます。ポインタが関数に渡されると、引数のアドレスが関数に渡され、このアドレスの内容がグローバルにアクセスされます。形式パラメータ(関数で使用されるパラメータ)に対して行われた変更は、実際のパラメータ(呼び出しプログラムで関数呼び出しに使用されるパラメータ)の元の値に影響を与えます。
例
| | / 39_func.c /
void func_c( int *x );
int main()
{
int i = 100;
int *a;
a = &i;
printf(“\n値は %d”, i);
func_c(a);
printf(“\n値は %d”, i);
return 0;
}
void func_c( int x )
{
(x) ++;
printf(“\n関数内の値は %d “, *x);
} |
上記のプログラムでは、3つの「printf」ステートメントがあり、2つはmain()関数内、1つは関数サブプログラム内です。最初のprintfステートメントの影響により、iの値は100として印刷されます。その後、関数呼び出しが行われ、関数内で値が変更され、1001になります。変更された値は再びmain()に返され、1001として印刷されます。
したがって、出力は次のようになります:
| | 値は100
関数内の値は101
値は101 |
関数呼び出しについての詳細
ポインタとの最初の出会いを経て、元々学ぼうとしていたことに戻りましょう – 2つのタイプの関数呼び出し: 値による呼び出しと参照による呼び出しです。引数は一般的に次の2つの方法のいずれかで関数に渡すことができます。
| | a. 引数の値を送信
b. 引数のアドレスを送信 |
2. 値による呼び出し
最初の方法では、呼び出し関数の各実際の引数の「値」が、呼び出された関数の対応する形式引数にコピーされます。この方法では、呼び出された関数内で形式引数に対して行われた変更は、呼び出し関数内の実際の引数の値に影響を与えません。次のプログラムは値による呼び出しを示しています。
| | / 40_callbyvalue.c /
void swap( int x, int y )
int main( )
{
int a = 10, b = 20;
swap( a ,b );
printf(“\n a = %d, b = %d “, a, b);
return 0;
}
void swap( int x, int y )
{
int t;
t = x;
x = y;
y = t;
printf(“\nx = %d, y = %d”, x, y);
} |
上記のプログラムの出力は次のようになります:
| | x = 20 y = 10
A = 10 b = 20 |
注意: aとbの値は、xとyの値を交換した後も変更されないことに注意してください。
3. 参照による呼び出し
今回は、呼び出し関数内の実際の引数のアドレスが、呼び出された関数の形式引数にコピーされます。これは、これらのアドレスを使用して実際の引数にアクセスできることを意味し、それらを操作できるようになります。次のプログラムはこの事実を示しています。
| | 41_callbyref.c /
void swap( int x, int y )
int main()
{
int a = 10, b = 20;
swap( &a, &b);
printf(“\na = %d, b = %d”, a, b);
return 0;
}
void swap( int x, int y )
{
int t;
t = x; x = y; y = t;
} |
上記のプログラムの出力は次のようになります:
| | A = 20, b = 10 |
注意: このプログラムは、xとyに保存されたアドレスを使用して、aとbの値を交換することに成功しています。通常、Cプログラミングでは値による呼び出しを行います。つまり、一般的に実際の引数を変更することはできません。しかし、必要に応じて、参照による呼び出しを通じて常に実現できます。
参照による呼び出しを賢く使用することで、一度に複数の値を返すことができる関数を作成できます。これは通常は不可能です。以下のプログラムで示します。
| | / 42_callbyref.c /
void areaperi(int r, float a, float p)
int main()
{
int radius;
float area, perimeter;
printf(“\n円の半径を入力してください:”); scanf(“%d”, &radius);
areaperi(radius, &area, &perimeter);
printf(“\n面積 = %f “, area);
printf(“\n周囲 = %f”, perimeter);
return 0;
}
void areaperi(int r, float a, float p)
{
a = 3.14 r r; p = 2 3.14 r;
} |
そして出力は次のようになります:
| | 円の半径を入力してください 5
面積 = 78.500000
周囲 = 31.400000 |
ここでは、radiusの値を渡していますが、areaとperimeterのアドレスを渡しています。そして、アドレスを渡しているため、aとpに格納されたアドレスの値を変更すると、main内で変更が有効になります。したがって、関数areaperi( )から制御が戻ると、areaとperimeterの値を出力できるようになります。
このようにして、呼び出された関数から2つの値を返すことができ、returnステートメントの制限を克服しました。これは、一度に1つの値しか返すことができません。
VII. ローカルとグローバル変数
識別子のスコープに応じて、変数は次のように宣言されます。
| | / 42_globalid.c /
int i=4000; / グローバル変数の宣言/
int main()
{
int a=10, b=20; / ローカル変数 /
int i=100; / ローカル変数 /
printf(“%d %d”, a, b);
printf(“\nローカルi : %d”, i); / ローカル変数へのアクセス /
printf(“\nグローバルi : %d “, ::i); / グローバル変数へのアクセス /
return 0;
} |
注意: スコープ解決 ( :: ) 演算子はC++でのみ使用可能です。
VIII. ストレージクラス指定子
ここまでの観点から、変数の宣言にはすでに慣れています。変数を完全に定義するには、その「型」だけでなく、「ストレージクラス」も指定する必要があります。
このセクションによれば、変数は「データ型」だけでなく、「ストレージクラス」も持っています。
ストレージクラスは4種類あります
| | 1. 自動ストレージクラス
- レジスタストレージクラス
- 静的ストレージクラス
- 外部ストレージクラス |
1. 自動ストレージクラス
| キーワード | auto | |
| ストレージ | メモリ | |
| デフォルト値 | Null | |
| スコープ | 変数が定義されたブロックにローカル | |
| 生命 | ブロックの実行まで |
例:
| | / 43_auto.c /
#include
int main()
{
auto int i, j;
printf(“%d %d”, i, u);
return 0;
} |
2. レジスタストレージクラス
| キーワード | register | |
| ストレージ | CPUレジスタ | |
| デフォルト値 | Null | |
| スコープ | 変数が定義されたブロックにローカル | |
| 生命 | ブロックの実行まで |
例:
| | / 44_register.c /
#include
int main( )
{
register int i, j;
for(i=1;i<=10;i++)
printf(“\n%d”, i);
return 0;
} |
3. 静的ストレージクラス
| キーワード | static | |
| ストレージ | メモリ | |
| デフォルト値 | ゼロ | |
| スコープ | 変数が定義されたブロックにローカル | |
| 生命 | 異なる関数呼び出し間で変数の値が持続する |
例:
| | / 45_static.c /
#include
void add();
int main()
{
add();
add();
add();
return 0;
}
void add()
{
static int i = 1;
printf(“%d\n”,i++);
} |
4. 外部ストレージクラス
| キーワード | extern | |
| ストレージ | メモリ | |
| デフォルト値 | ゼロ | |
| スコープ | グローバル | |
| 生命 | プログラムの実行が終了するまで |
例:
| | / 46_extern.c /
#include
int i;
void add(); / 外部変数 /
int main( )
{
extern j=10; / 外部変数 /
for(i=1;i<=10;i++)
add();
return 0;
}
void add( )
{
j++;
printf(“%d %d\n”, i, j);
} |
新しい投稿を受信箱で受け取る
スパムはありません。いつでも購読を解除できます。