ポインタ(pointer)
データとアドレス
- データはメモリのデータ領域に置かれる
- メモリの場所を表すものをアドレスという
- 従って、変数はその値とアドレスという2つの属性を持つ
(他に名前、型という属性も持つ)
ポインタ
- ポインタはその値としてアドレスを持ち、個々のデータを指す
- 記号定数 NULL はゼロで、
何も指さないポインタ、
異常事態の発生を表すことにも使われる
ポインタ変数の定義
型 *ポインタ名;
- この型はポインタが指すものの型である
「〜へのポインタ」ということになる
*ポインタ
- * は間接参照演算子である
- ポインタの値ではなく、
そのポインタが指している(そのアドレスに存在する)ものになる
&変数名
- & はアドレス演算子である
- 変数の値ではなく、そのアドレスになる
- 渡した先でその値を変更されたい場合などに使う(例:scanf() の引数)
| |
|
ポインタの用途
- 戻り値以外の方法で関数から値を返してもらう
→返して欲しい場所(アドレス)をポインタとして渡す
- 複数の値を関数から返してもらう
←Cの関数は1価関数で値を1つしか返すことができないから
- 配列を引数として関数に渡す
実際は配列の先頭アドレスがポインタとして渡るだけ!
→配列のコピーを渡したければ、配列を構造体のメンバーにする
- 可変長の配列を実現する
- 連結リスト等のデータ構造を実現する
↑これが本当のポインタの使い方!!
変数の内容を入れ替える方法
/* 変数の内容を入れ替える1 */
#include <stdio.h>
main()
{
int i = 1;
int j = 2;
int tmp; /* テンポラリ領域 */
printf("i = %d, j = %d\n", i, j );
/*
i = j;とするとiの内容が消失してしまう!
*/
tmp = i; /* まずiの値を退避 */
i = j; /* jの値をiに移す */
j = tmp; /* t(退避していたi)の値をjに移す */
printf("i = %d, j = %d\n", i, j );
}
/* end of exc1.c */
整数を入れ替える関数を作ってみよう
/* 変数の内容を入れ替える2 */
#include <stdio.h>
void swap( int x, int y )
{
int tmp;
tmp = x;
x = y;
y = tmp;
}
main()
{
int i = 1;
int j = 2;
printf("i = %d, j = %d\n", i, j );
swap( i, j );
printf("i = %d, j = %d\n", i, j );
}
/* end of exc2.c */
|
|
- 値呼び出し(call by value)なので、
その値( x, y )を入れ替えても、実体( i, j )は入れ替わらない!
/* 変数の内容を入れ替える3 */
#include <stdio.h>
void swap( int *x, int *y )
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
main()
{
int i = 1;
int j = 2;
printf("i = %d, j = %d\n", i, j );
swap( &i, &j );
printf("i = %d, j = %d\n", i, j );
}
/* end of exc3.c */
|
|
- 値呼び出し(call by value)なので、
入れ替えたい実体のアドレス( &i, &j )を渡す必要がある!
/* 円の面積と円周を求める */
#include <stdio.h>
#define PI 3.1415926535
main()
{
void rcc( float r, float *circle, float *circumference ); /* 関数rccの宣言 */
float r, s, l;
printf("半径を入力して下さい:");
scanf("%f", &r );
rcc( /* ここを書く! */ ); /* 関数rccの呼び出し */
printf("半径が %f の円の面積は %f で、円周は %f です。\n", r, s, l );
}
void rcc( float r, float *circle, float *circumference ) /* 関数rccの定義 */
{
*circle = PI * r * r;
*circumference = 2 * PI * r;
}
/* end of rcc.c */
/* 加減乗除を表示する */
#include <stdio.h>
main()
{
void asmd( float x, float y, float *a, float *s, float *m, float *d );
float a, b, add, sub, mul, div;
printf("2数を(スペースで区切って)入力して下さい:");
scanf("%f %f", &a, &b );
asmd( a, b, &add, &sub, &mul, &div );
printf("2数は %f と %f\n", a, b );
printf("和:%f, 差:%f, 積:%f, 商:%f\n", add, sub, mul, div);
}
/* 2数の加減乗除を計算する関数 */
void asmd( float x, float y, float *a, float *s, float *m, float *d )
{
/* ここを書く! */
}
/* end of asmd.c */
- 除数が 0 になることを考えずに作ると、2つ目の数(b)が 0 のとき除算できないので、正しく処理されないかエラーが生じてしまう。
...と言う訳で、除数 0 の場合も考慮に入れて、
- asmdを改良し、通常は 0 を返し、除数が 0 の場合には、
除算結果が無効であることを示す為に、1 を返すようにせよ!
int asmd( float x, float y, float *a, float *s, float *m, float *d )
- mainを改良して、除数が 0 の場合の商は、「商:除数0」と表示するようにせよ!
- さらにmainを改良し、繰り返し2数の加減乗除を計算して表示するようにせよ!
- 入力された2数が共に 0 の場合、その演算結果を表示して終了するものとする。
ポインタの練習問題へ