12月 14日


第10章

関数の引数
教科書 p.226

(復習)C言語の関数呼出しは値渡しである (List 10-1)。 つまり、ふつうは関数の中で呼出し側の変数を変更することはできない。

アドレス
教科書 p.227
C言語の変数には(register変数などの例外を除き)メモリ上のアドレス(address)がある。
アドレス演算子
教科書 p.228

単項&演算子を変数(や配列の要素など=演算子の左辺に置けるもの)に適用すると、 そのアドレスが得られる。 単項&演算子はアドレス演算子とも呼ばれる。 (List 10-2

アドレスをprintfで出力するときの書式指定は%pである。

ポインタ
教科書 p.229
アドレスを変数に格納することができる。このような変数をポインタという。 ポインタ型の変数の宣言は*を変数名の前につける。 (List 10-3

    int sato = 178;
    int *isako;
    isako = &sato;    /* isakoは int型のオブジェクトのアドレスを格納することができる。 */
                      /* “isakoはsatoを指す”という。 */
間接演算子
教科書 p.231
ポインタの前に単項*演算子をつけると、それが指すオブジェクトそのものを表す。 単項*演算子は間接演算子とも呼ばれる。 (List 10-3
    *hiroko = 180;    /* hirorkoの指すオブジェクトに180を代入 */
                      /* この例の場合 masaki = 180と同じ効果を持つ */
関数の引数としてのポインタ
教科書 p.232
関数の引数としてポインタを渡すと、次のようなことが可能になる。 (List 10-4, List 10-5, List 10-7 cf. List 10-1, List 10-8, )
scanf関数とポインタ
教科書 p.216
scanf関数でint型(%dに対応)や、 double型(%lfに対応)を受取るとき、変数の前に&をつけたのも、 関数から呼出し側の変数の値を変更するためである。
ポインタの型
教科書 p.238

ポインタの型は、それが指すオブジェクトの型と正しく対応しなければならない。 (List 10-9

この点は、ポインタのインクリメント・デクリメント(後述)のとき、さらに重要になる。

ポインタと配列
教科書 p.240

ポインタは配列の要素を指すこともできる。 (List 10-10

    int vc[5] = {10, 20, 30, 40, 50};
    int *ptr = &vc[0]; 
&vc[0]で配列の先頭要素のアドレスを表す。 (p.177 演算子の一覧表参照)

注意:

ポインタのインクリメント・デクリメント
教科書 p.255
ポインタをインクリメント(++)・デクリメント(--)すると、 それぞれ配列の次の要素・前の要素を指すようになる。
配列の受渡し
教科書 p.244
関数の仮引数の宣言としては、int vc[]int *vcはまったく同一である (List 10-13)。 このプログラムの関数int_setの定義は、
    void int_set (int *vc, int no, int val) { 
        … 
    }
と書いてもまったく意味は同じである。
ポインタ使用上の注意

以下のプログラムはどこが間違っているか?

  1. 初期化されていないポインタ
  2. #include  <stdio.h>
    
    /*--- n1とn2の和・差をsumとdiffに格納 ---*/
    void sum_diff(int n1, int n2, int *sum, int *diff)
    {
        *sum  = n1 + n2;
        *diff = (n1 > n2) ? n1 - n2 : n2 - n1;
    }
    
    int main(void)
    {
        int  na, nb;
        int *wa, *sa;  /* ← ここを変えた */
    
        puts("二つの整数を入力してください。");
        printf("整数A:");   scanf("%d", &na);
        printf("整数B:");   scanf("%d", &nb);
    
        sum_diff(na, nb, wa, sa);
    
        printf("和は%dです。\n差は%dです。\n", *wa, *sa);
    
        return (0);
    }
    
  3. 迷子のポインタ
  4. #include  <stdio.h>
    
    int *sum_diff(int n1, int n2)
    {
        int ret[2];
    
        ret[0]  = n1 + n2;
        ret[1]  = (n1 > n2) ? n1 - n2 : n2 - n1;
    
        return &ret[0];  /* 先頭要素へのポインタを返す */ 
    }
    
    int main(void)
    {
        int  na, nb;
        int *wasa; 
    
        puts("二つの整数を入力してください。");
        printf("整数A:");   scanf("%d", &na);
        printf("整数B:");   scanf("%d", &nb);
    
        wasa = sum_diff(na, nb);
    
        printf("和は%dです。\n差は%dです。\n", wasa[0], wasa[1]);
    
        return (0);
    }
    
大抵の場合、問題がないように実行されてしまうので、こういう間違いは余計に恐い。

戻る


Koji Kagawa(kagawa@eng.〜)