C_pointer


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

ポインタの利点(再度改変の必要あり。)

今日はCのお話です。C言語でポインタ嫌いになった人も多々だと思いますが、
ここではポインタの利点を説明して、
ゆくゆくはC++でnew演算子をちゃんと使用してもらえればなと思います。

まずは基本の変数ポインタ

int* a;

こうやるとint型のポインタができる。
int *a;

これでもいい。ただ個人的には「int型アドレスを格納する」変数なので上の方を押します。
構造体のポインタも同様に、

struct Structure *a;

ということができます。

次に関数のポインタ

C言語の構文は変数と関数ですから、関数にもポインタがあります。
int型で引数に2個のintを引数に取る関数のポインタは次のように表します。

int (*func)(int,int);

ってことです。これと同じ型の関数を func = ... として代入可能です。

メリット

その1:固定長

アドレス長はcpuのアーキテクチャに依存します。
(?大体はOSが32bitだったら32bitのアドレス長、64bitだったら64bitになる:要ソース)
ポインタ変数はアドレス長分だけ確保されるのでどんな型のポインタでさえ固定な長さの領域になります。

32bit以上の長さをもつ構造体などを引数に取った関数を作る場合は、
アドレス渡しにして仮引数にポインタ変数を定義した方がコピーする量が減りますね。
(グローバルだから関係ないぜとか言わない)

ただ、値渡しでも構わないので見やすくなる程度に利用するのが吉。

その2:グローバルを減らせる、関数内で引数に渡したアドレスを参照できる。


#include <stdio.h>
struct _lpoint{
 double x;
 double y;
}DPOINT;
struct _data{
 DPOINT point;
 int hp;
 const char* name;
}DATA;
void initalizeData(POINT *pt,double x,double y,int hp,const char* namePt){
 pt->point.x = x;
 pt->point.y = y;
 pt->hp = hp;
 pt->name = namePt;
}

int randMax(int num){
 return rand() %num;
} 

const char* nameArray[4]={
 "hoge","huga","hage","hige"
};

int main(void){
 DATA dt[4];
 for(i=0;i<4;i++){
  initalizeData(&dt[0],randMax(64),randMax(64),3,nameArray[i]);
 }
}

こんな感じに初期化用関数を作っておくと、記述がすっきりしますね。
(あとで:CONSTについてのメモ...(未記入)


その3:プログラムが柔軟になる

例えばArray[12]に適応したいサブルーチンがあったとして、
毎回forループを書くのが面倒なのでMap関数を作ってみる。
Map関数は関数型言語でおなじみの関数です。
C++やJavaのmapコンテナとはまたべつですね。(連想配列とか
void map(int array[],int length,void (*func)(int* data)){
 int i;
 for(i=0;i<length;i++){
  func(&array[i]);
 }
}

要素の値を直接弄りたいので、渡す関数の引数(func)の引数はポインタにしておきます。
で利用するときはこんな感じ。

void setRandomNumber(int* elm){
 //乱数を格納する
 *elm = rand()%8;
}
void elementFunction(int* elm){
 //中の要素を%8して余り
 //左からその分シフトしてprintfする
 const char shift[]="________\0";
 int shiftNum = *elm%8;
 printf("elm%2d:%s*\n",*elm,&shift[8-shiftNum]);
}
int main(void){
 int array[32];
 map(array,32,setRandomNumber);
 map(array,32,elementFunction);
 scanf("%d",&array[0]);
}

arrayとかの処理が書いてあると、プログラマの脳みそを使ってしまうので、
まわす対象の配列などはハードコーディングしてしまって、専用の関数を作ってしまう。
そうするとあとは適応する関数だけ指定する形式まで落とし込めます。
紹介はしましたけど、Cだと使いどころってなかなか無いのかなとか思ったり。

オブジェクトを利用したJavaやC++や、
関数定義したときにそのまま定義文が参照として評価される言語では、
この構造で一度プログラムを作っておくと再利用しようとしたときに「オーマンマ」とか言っちゃうでしょう。


ちなみに関数を引数に取って実行する場合、
その引数に入れた関数の事をコールバック関数と呼んだりします。

C++でのオブジェクトをポインタで渡す利点はまた今度。動的オブジェクトの項で。