C言語で関数の引数にポインタを渡す【ポインタの値渡し】
- 作成日: 2021-09-24
- 更新日: 2024-03-22
- カテゴリ: C言語
関数の引数にポインタを渡す方法
C言語の関数の引数にポインタを渡す方法を解説します。
関数の引数にポインタを使えるといろいろな処理のバリエーションが増えます。
たとえば関数呼び出し側の変数に関数の結果を保存するなどの処理も可能です。
この記事では具体的に関数の引数にポインタを渡す方法を見ていきたいと思います。
C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。
関連記事
C言語で関数から複数の戻り値を返す【ポインタ、構造体】
C言語の関数で戻り値にポインタを使う
C言語の関数ポインタの使い方
C言語の関数ポインタをtypedefする方法【型定義】
C言語の関数ポインタを引数に渡す方法
- C言語で関数の引数にポインタを渡す【ポインタの値渡し】
ポインタ変数とアドレス値の定義
最初にポインタ変数とアドレス値の用語の定義です。
ポインタ変数は変数のアドレス値を保存する変数。
アドレス値は変数のメモリ上のアドレスのことを言います。
関数にポインタを渡す場合、これらの用語の把握が一番重要です。
たとえば関数呼び出し時に、呼び出し側で取り出すのが変数のアドレス値です。
そのアドレス値を関数の引数(ポインタ)に渡します。
これらの用語を意識するようにしてください。
関数の引数にポインタを使うメリット・デメリットは?
関数の引数にポインタを使うメリットは↓になります。
- 設計がシンプルになる
- 処理が高速になる
関連記事
C言語のポインタのメリットとは?コピーしますかメモリを共有しますか
逆にデメリットは↓になります。
- 不正なポインタでセグフォする可能性がある
関数の引数にポインタを使うと、関数などの設計がシンプルになります。
これはポインタの柔軟性によるものです。
またポインタを使うと処理が高速になります。
これはコピーよりポインタを使ったほうが早いからです。
具体的には構造体を使った関数が考えられます。
構造体変数に処理の結果を保存したい場合、関数に構造体のポインタを渡します。
そうすると関数はそのポインタから構造体のメンバにアクセスできます。
こうすることで設計がシンプルになり、処理が高速になります。
関数の引数にポインタを使う場合、設計はシンプルになり処理は高速になりますが、まさに至れり尽くせりですね。
ただし不正なポインタを渡した場合は解決しづらいバグになる場合もありますので注意が必要です。
関数の引数をポインタで定義する方法
それでは関数の引数をポインタで定義してみましょう。
実際のC言語のコードを紹介します。
int型のポインタを引数にする
int
型のポインタを関数の引数にする場合は↓のようにします。
void f1(int *arg) {
}
f1
という関数にはint
型のポインタarg
が引数になっています。
これでこの関数にはint
型の変数のアドレス値を渡すことができます。
文字列のポインタを引数にする
const char
型のポインタを関数の引数にするには↓のようにします。
void f2(const char *arg) {
}
f2
と言う関数はconst char
型のポインタarg
が引数になっています。
これでC言語の文字列をこの関数に渡すことが出来ます。
複数のポインタを引数にする
複数のポインタを引数にする場合は例えば↓のような関数が考えられます。
void f3(int *arg1, double *arg2, const char *arg3) {
}
↑の場合、arg1
はint
型のポインタ、arg2
はdouble
型のポインタです。
arg3
はconst char
型のポインタになります。
関数に変数のアドレスを渡す
ポインタの引数を持った関数に変数のアドレス値を渡す方法を見てみます。
&
(アンパサンド)を使って変数のアドレス値を取り出し、そのアドレス値を関数に渡します。
具体的に見ていきます。
アンパサンドで変数のアドレス値を取り出す
変数の頭に&
(アンパサンド)を付けると、その変数のアドレス値を取り出すことができます。
たとえばint
型の変数a
があって、その変数a
のアドレス値を取り出したい場合は↓のようにします。
int a = 1;
printf("%p\n", &a);
// 000000000062FE1C
↑では変数a
のアドレス値を取り出して、printf()
関数に渡しています。
書式指定子%p
でアドレス値を出力すると↑のような結果になります。
(結果は環境によって変わります)
アドレス値を関数の引数に渡す
では&
(アンパサンド)で取り出した変数のアドレス値を関数の引数に渡してみます。
関数func
があり、その関数の引数にint
型の変数のアドレス値を渡します。
void func(int *a) {
}
int main(void) {
int a = 1;
func(&a);
return 0;
}
↑のようにすると関数func
にint
型の変数a
のアドレス値を渡すことができます。
関数にポインタ変数を渡す
では次に関数にポインタ変数を渡してみましょう。
ポインタ変数は普通に参照するとポインタ変数に保存されているアドレス値が参照されます。
そのためポインタ変数を関数の引数に渡すだけで関数にアドレス値を渡すことが出来ます。
具体的に見ていきます。
int型のポインタ変数を渡す
int
型のポインタ変数を関数に渡す例です。
void func(int *arg) {
}
int main(void) {
int a = 1;
int *p = &a;
func(p);
return 0;
}
↑の場合、main
関数内のポインタ変数p
には変数a
のアドレス値が入っています。
そのポインタ変数p
を関数func
に渡しています。
文字列のポインタ変数を渡す
文字列のポインタ(const char
型のポインタ)変数を関数に渡す例です。
void func(const char *arg) {
}
int main(void) {
const char *a = "hi";
func(a);
return 0;
}
C言語の文字列の場合は変数はポインタか配列になります。
そのためそのまま関数の引数に渡すことができます。
複数のポインタ変数を渡す
複数のポインタ変数を関数に渡したい場合は↓のようなコードが考えられます。
void func(int *a, double *b, const char *c) {
}
int main(void) {
int a = 1;
int *ap = &a;
double b = 2.3;
double *bp = &b;
const char *c = "hi";
func(ap, bp, c);
return 0;
}
↑の場合、関数func
はint
型のポインタである引数a
とdouble
型のポインタである引数b
を持っています。
またconst char
型の文字列のポインタc
も持っています。
これらの引数にそれぞれ同じ型のポインタ変数を渡しています。
ポインタの引数を関数内で使う方法
ポインタの引数を関数内で参照するにはどうしたらいいのでしょうか?
ポインタを通して変数の値を書き換えるには?
具体的に見ていきたいと思います。
アスタリスクで実体化して参照する
*
(アスタリスク)でポインタを参照することでポインタを通して変数の値を参照できます。
↓の場合を見てみます。
#include <stdio.h>
void show(int *p) {
printf("%d\n", *p); // 1
}
int main(void) {
int a = 1;
show(&a);
return 0;
}
main
関数内の変数a
のアドレスをshow()
関数に渡しています。
このshow()
関数内ではポインタp
をアスタリスクで実体化して変数a
の値を参照しています。
その結果をprintf()
で出力しています。
結果は「1」になります。
アスタリスクで実体化して代入する
*
(アスタリスク)でポインタ変数を参照し、そこに値を代入すれば、関数の呼び出し側の変数の値を書き変えることが可能です。
#include <stdio.h>
void change(int *p) {
*p = 2;
}
int main(void) {
int a = 1;
change(&a);
printf("%d\n", a); // 2
return 0;
}
↑の場合、main
関数内の変数a
のアドレス値をchange()
関数に渡しています。
change()
関数は内部でポインタp
を*
で参照し、値2
を代入しています。
こうすることでmain
関数側の変数a
の値が2
に書き変わります。
printf()
の結果は「2」になります。
関数の引数にポインタを使った具体例
関数の引数にポインタを使う処理の具体例を紹介します。
1~10の合計を計算する関数sum
「1~10」の間の値の合計を計算する関数sum()
です。
#include <stdio.h>
void sum(int *result, int beg, int end) {
*result = 0;
for (int i = beg; i <= end; i += 1) {
*result += i;
}
}
int main(void) {
int result;
sum(&result, 1, 10);
printf("result[%d]\n", result); // 55
return 0;
}
sum()
を使うにはまず呼び出し側で結果を保存する変数(result
)を定義しておきます。
そしてその変数のアドレス値をsum()
関数の第1引数に渡します。
sum()
関数は内部でbeg
とend
の間だけfor
文を回し、そのカウント変数をポインタ変数result
に加算していきます。
sum
関数の呼び出し側で変数result
の値を出力します。
結果は「55」になります。
構造体のメンバを設定する関数
関数の引数には構造体のポインタも使うことができます。
構造体のポインタを使えば、関数内で構造体のメンバにアクセスできます。
#include <stdio.h>
struct Animal {
int age;
double weight;
};
void set_animal_params(struct Animal *animal, int age, double weight) {
animal->age = age;
animal->weight = weight;
}
int main(void) {
struct Animal animal;
set_animal_params(&animal, 20, 32.1);
printf("%d %f\n", animal.age, animal.weight); // 20 32.100000
return 0;
}
↑のset_animal_params()
関数は構造体struct Animal
のメンバ(age
, weight
)を変更する関数です。
set_animal_params()
の第1引数に構造体変数のアドレス値を渡しています。
このような設計で構造体を扱うのはC言語では非常にポピュラーな方法です。
代表例としてはfopen()
系の関数などが挙げられます。
おわりに
今回はC言語の関数の引数にポインタを使う方法を解説しました。
関数とポインタを組み合わせるとC言語では以上のような便利な処理が可能になります。
ぜひマスターしておきたいところですね。
🦝 < 関数とポインタはマブダチ
🐭 < 俺らの相性抜群だぜ