ログイン
kid's world

ポインタを利用した値の返し方

ポインタを利用した値の返し方

複数の値をポインタを使って返す

さて,関数の戻り値は1つだけであるが,複数の値を一度に返したい場合はどうすればよいのだろうか。場合によっては返さなければならない値が1つとは限らない場合も出てくるだろう。そのようなときは,「引数を使って」値を返すことができる。

引数を使って値を返すというのはなんとも奇妙な話ではあるが,すでに解説していることにお気づきだろうか。その関数とはscanf関数である。

scanf関数はキーボードから入力された値を,引数を介して変数に返している。そこでポイントとなるのは,変数をそのまま引数に渡しているのではなく,「変数へのポインタ」を指定しているところにある。なぜ変数へのポインタを引数に渡すのだろうか。それは,変数へのポインタによって,変数の内容を書き換えることができるからである。

したがって,List 7のようにポインタを引数として複数受け取るように関数を作れば,一度の呼び出しで複数の値を返すことができるわけである。このプログラムは,第1引数に与えられた数値を1の位と10の位以上の値に分ける関数である。

List 7: 1の位と10の位以上を分ける関数

#include <stdio.h>

void foo(int i, int *m, int *d);

void foo(int i, int *m, int *d)
{
  *m = i%10;
  *d = i/10;
}

main()
{
  int i,j;
  
  foo(123,&i,&j);
  printf("%d , %d\n",i,j);
}

文字列を返す時の注意点

同じ要領で文字列を返すような関数を作ることができる。しかし,ここでメモリがどのように使われているのかに注意しなければならない。

ポイントは,関数の中で作られるローカル変数は「その関数の実行が終わるとメモリ上から姿を消す」ということである。ローカル変数へのポインタは,その関数の実行が終わった瞬間に無効となると考えなければならない。よって,ローカル変数へのポインタを返してはならないのである。では,どうすれば文字列を返す関数を作ることができるのだろうか。そのメモリ空間はどのように確保すればよいのだろうか。

呼び出された側の関数の中で,malloc関数などを使ってメモリを確保するのはあまり賢い方法ではない。いちばんよいのは,その関数を呼び出す側でそのメモリを確保するという方法である。呼び出された側の関数は,「メモリがすでに確保されている」という前提のもとで,メモリに直接返したい文字列を書き込むだけにするのである。実際,ほとんどの関数がそのような設計になっている。これは特別な方法ではなく,よく考えてみればFig. 4と何ら変わるところはない。配列やmallocなどで文字列用の領域をメモリ上に確保しておくというところが異なるだけで,そのほかはint型変数と同じように,呼び出し元で作成した変数へのポインタを渡すというだけなのである。

Fig. 4: ポインタを利用した値の返し方

/c/function-fig4.png

しかし,「いったい何バイトの領域を確保しているのか」は呼び出された側はわからないために困る場合がある。そういう場合は,何バイト確保したのかをもう1つの引数で指定するという方法もある。その例をList 8に示す。sfoo関数は,指定された長さのメモリが確保された配列に対して,その長さのぶんだけ「abcd...」とアルファベットを書き込んでいく関数である。

List 8: 文字列を返す関数

#include <stdio.h>

void sfoo(char *str, int len);

void sfoo(char *str, int len)
{
  int i;
  
  for(i=0; i<len-1; i++)
    str[i]='a'+i;
  str[i]='\0';
}

main()
{
  char abc[20];
  
  sfoo(abc, 20);
  printf(abc);
}

この関数は,第1引数strに文字列を書き込む。第2引数には長さ,すなわち書き込んでもよいバイト数を指定してもらう。str[len-1]までが,使ってもよい領域となるわけである。

変数iは配列の添え字として使っており,for文では,strのi番目に'a'+iの文字を代入している。for文を抜けたあと,len-1番目に'\0'を代入して,文字列の終わりとしている。このようにして,strはlenの長さだけの文字列が書き込まれたことになる。

おわりに

関数は「難しいことを簡単にする1つのツール」だと考えていただきたい。どんなに複雑なプログラムも,実は簡単なことの集まりであることが多い。その簡単なものを1つ1つの関数として作り,あとから積み木を重ねていくように関数を組み合わせていけばよいのである。そうすることによって,難しいプログラムを簡単に作っていくことができるのである。


アルゴリズムとは」へ進む

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告