プログラミング論II

プログラミング論 II
2009年10月15日
ポインタ
http://www.ns.kogakuin.ac.jp/~ct13140/Prog.2009/
1
見つかった誤り
if( x = 3 ){ ... }
"x=3"は比較ではなく、代入.
x += 2 は、"xが2増える"が,
x =+ 2 は、"x に +2 を代入"となる.
つまり "x = +2"となってしまう
D-2
見つかった誤り
x = x+1; はOK.
x+1 = x; はNG.
代入は 右の値を左に入れる.
x = 3 はOKだが, 3 = x はNG.
D-3
見つかった誤り
• #define MAX 100
は,MAXを100に置き換えてからコンパイルする
– MAXという変数があるわけではない!
#define MAX 100
i=MAX;
#define MAX 100
MAX=30;
MAXという変数が
あるわけではない
これを
i=100; コンパイル
これを
100=30; コンパイル????
D-4
概要
• ポインタ
– 難易度が高いが,極めて重要
– & と * の2種類しかない.
• ちなみに…
–前期最重要事項 : 関数
–後期最重要事項 : pointer
D-5
5
ポインタ
• なにかを「指す」ものがポインタである.
• C言語ではアドレスを理解すれば良い.
• 一般に理解が難しいとされる
D-6
メモリとアドレス
• 計算機はメモリにデータを保存している.
– 通常1バイト(8bit)単位で管理される.
– 1バイトの記憶領域が大量にある.
• 各バイトには,固有の通し番号(住所,アドレス)
がついている.
それぞれのメモリに
1バイトのデータを
記憶できる.
各1バイトに固有の
住所がついている.
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
7
100 56
23
53
1バイトの記憶領域が10個ある例.
45
95
2
0
65
D-7
変数の記憶領域
• 変数を作ると,当然メモリ上にそのための記憶領
域が自動的に確保される.
char abc; /* char型変数を1個用意 */
変数abcの内容は,
4番地に記録する
ことに決めたとする.
(計算機が自動で行う)
abc
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
7
100 56
23
53
45
95
2
0
65
D-8
変数の記憶領域
• 変数を作ると,当然メモリ上にそのための記憶領
域が自動的に確保される.
char abc; /* char型変数を1個用意 */
char *p;
&abc は,「変数abcは
メモリの何番地か」を返す.
abc = 7;
pには「4番地」が入る.
p = &abc;
7では無いことに注意!
abc
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
7
100 56
23
7
45
95
2
0
65
D-9
&演算子
• &演算子はアドレスを調べる演算子.
• 変数に&を付けると,そのアドレスが得られる.
void main(){
char abc;
char *p;
p = &abc;
printf("abcのアドレスは%pです.\n", p);
}
実行結果
abcのアドレスは0013FF7Cです.
D-10
&演算子
void main(){
char abc, def;
char *p;
p = &abc;
printf("abcのアドレスは%pです.\n", p);
p = &def;
printf("defのアドレスは%pです.\n", p);
}
実行結果
abcのアドレスは0013FF7Cです.
defのアドレスは0013FF78です.
D-11
&演算子
void main(){
char abc, def, ghi;
printf("アドレスは%p %p %pです.\n",
&abc, &def, &ghi);
}
実行結果
アドレスは0013FF7C 0013FF78 0013FF74です.
D-12
&演算子
void main(){
char abc[5];
printf("アドレスは%p %p\n%p %p %pです.\n",
&(abc[0]), &(abc[1]),
&(abc[2]), &(abc[3]), &(abc[4]));
}
実行結果
アドレスは0013FF78 0013FF79
0013FF7A 0013FF7B 0013FF7Cです.
D-13
&演算子
void main(){
int abc[5];
printf("アドレスは%p %p\n%p %p %pです.\n",
&(abc[0]), &(abc[1]),
&(abc[2]), &(abc[3]), &(abc[4]));
}
int型は4バイト
実行結果
アドレスは0013FF6C 0013FF70
0013FF74 0013FF78 0013FF7Cです.
D-14
ポインタ変数
• アドレスを格納する変数
– 整数を格納できる変数があるように,
アドレスを格納する変数がある.
char ch; /* char型を格納する */
char *p; /* char型変数のアドレスを格納 */
p = &ch;
/* ch は"4番地"なので,pには"4番地"が入る
ch
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
7
100 56
23
7
45
95
2
0
65
D-15
アドレス型変数(ポインタ変数)
• アドレスを格納する変数
– 整数を格納できる変数があるように,
アドレスを格納する変数がある.
char ch; /* char型を格納する */
char *p; /* char型変数のアドレスを格納 */
p = &ch;
printf("アドレスは%pです\n", p);
ポインタ(アドレス型)をprintfで表示するには,
%p を使う.
D-16
*演算子
• アドレスの間接参照演算子.
• アドレスの中身にアクセスする.
変数a,b,pを宣言した.
char a, b; char *p;
それぞれ,メモリの
6番地,5番地,4番地が
割与えられたとする.
注意:実際はアドレスは1バ
イトではない.
p
b
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
D-17
*演算子
• アドレスの間接参照演算子.
• アドレスの中身にアクセスする.
char a, b; char *p;
変数aに53を代入.
a = 53;
つまり,メモリの6番地に
53を格納.
p
b
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
53
D-18
*演算子
• アドレスの間接参照演算子.
• アドレスの中身にアクセスする.
char a, b; char *p; &aで変数aのアドレスを得る.
変数aは6番地なので,
a = 53;
pには6番地が代入される.
p = &a;
注意:実際は「番地」という
単位はつかない.
p
b
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
6
番地
53
D-19
*演算子
• アドレスの間接参照演算子.
アドレス(ポインタ)に
• アドレスの中身にアクセスする. * を付けると,
そのアドレスの中身を
char a, b; char *p;
意味する.
a = 53;
pは「6番地」.
p = &a;
*pは「6番地の中身」
すなわち53
b = *p;
p
b
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
6
53
番地
53
D-20
*演算子
char a; char *p;
aが5番地に,
pが4番地に
割り当てられたとする.
p
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
D-21
*演算子
char a; char *p;
p = &a;
p
&a で,
aのアドレスを獲得.
&a は"5番地"である.
pに"5番地"が
格納される.
(メモリの4番地に
"5番地"が格納される)
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
D-22
*演算子
char a; char *p;
p = &a;
a = 8;
p
aに8を代入.
aは5番地なので,
メモリの5番地に
8が格納される.
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-23
*演算子
char a; char *p;
p = &a;
a = 8;
printf("%d", *p);
pは5番地.
*pは「5番地の中身」.
5番地には,
"8"が格納されているので,
8が表示される.
実行結果 8
実質,a と *p は同一.
p
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-24
*演算子
char a; char *p;
aが5番地に,
pが4番地に
割り当てられたとする.
p
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
D-25
*演算子
char a; char *p;
p = &a;
p
&a で,
aのアドレスを獲得.
&a は"5番地"である.
pに"5番地"が
格納される.
(メモリの4番地に
"5番地"が格納される)
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
D-26
*演算子
char a; char *p;
p = &a;
*p = 8;
pは5番地.
*pは「5番地の中身.
「5番地の中身」を
"8"にする.
結果,aが"8"になる.
p
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-27
*演算子
aを表示する.
当然,"8"が
表示される.
char a; char *p;
p = &a;
*p = 8;
printf("%d", a);
実質,「aへの代入」と
「*pへの代入」は
同一である.
実行結果 8
p
a
aへの値の代入は
行っていないが,
aの値が変わる.
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-28
*演算子
char a; char *p;
p = &a;
a = 7;
p
aに"7"を代入.
すなわち,
メモリの5番地に
"7"を格納.
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
7
D-29
*演算子
char a; char *p;
p = &a;
a = 7;
*p = 8;
p
pは「5番地」
*p=8 は,
「メモリ5番地を8にする」
aの値が変わってしまった.
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-30
*演算子
char a; char *p;
p = &a;
a = 7;
*p = 8;
printf("%d", a);
aの値を表示する.
当然,"8"が表示される.
実行結果 8
p
a
0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地
5
番地
8
D-31
アドレス型変数(ポインタ変数)
• アドレスを格納する変数
– 整数を格納できる変数があるように,
アドレスを格納する変数がある.
char
int
char
int
ch;
i;
*p0;
*p1;
/*
/*
/*
/*
整数や文字コードの入れ物 */
整数の入れ物 */
char型変数のアドレスの入れ物 */
int型変数のアドレスの入れ物 */
D-32
アドレス型変数(ポインタ変数)
char a;
/* a は char型 */
char *b; /* b は アドレス型 */
char c, *d, e, *f;
/* cは char型,d はアドレス型,
eは char型,f はアドレス型 */
char *g, h;
/* g はアドレス型, hはchar型 */
不慣れなうちは,この様な記述は避けるのが無難?
D-33
配列とアドレス(ポインタ)
• 配列の場合,アドレスは連続している.
– char ch[10]が100番地~109番地に割り振られ
た例.
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
D-34
配列とアドレス(ポインタ)
void main(){
char abc[5];
printf("アドレスは%p %p\n%p %p %pです.\n",
&(abc[0]), &(abc[1]),
&(abc[2]), &(abc[3]), &(abc[4]));
}
実行結果
アドレスは0013FF78 0013FF79
0013FF7A 0013FF7B 0013FF7Cです.
D-35
配列とアドレス(ポインタ)
void main(){
int abc[5];
printf("アドレスは%p %p\n%p %p %pです.\n",
&(abc[0]), &(abc[1]),
&(abc[2]), &(abc[3]), &(abc[4]));
}
実行結果
アドレスは0013FF6C 0013FF70
0013FF74 0013FF78 0013FF7Cです.
D-36
配列とアドレス(ポインタ)
• 配列の場合,アドレスは連続している.
– int
&(
&(
&(
i[3]が100番地~111番地に割り振られた例
i[0] ) は,100番地
(この例では)
int型は
i[1] ) は,104番地
4バイトである.
i[2] ) は,108番地
i[0]
100
番地
101
番地
102
番地
i[1]
103
番地
104
番地
105
番地
106
番地
i[2]
107
番地
108
番地
109
番地
110
番地
111
番地
D-37
配列とアドレス(ポインタ)
char ch[12];
char *p;
p = &(ch[0]);
printf("%p\n", p);
p = ch;
printf("%p\n", p);
実行結果
0013FF74
0013FF74
添え字を付けずに
([0]などを付けずに)
配列名だけを書くと,
配列の先頭のアドレス
を意味する.
この場合,ch と
&(ch[0]) は同義.
D-38
ポインタ演算
char ch[10]; char *p;
p = ch;
printf("%p\n", p);
p++;
printf("%p\n", p);
実行結果
0013FF74
0013FF75
D-39
配列とアドレス(ポインタ)
char ch[10]; char *p;
p = ch;
pには,
ch[10]の先頭アドレスである
100番地が代入される.
ch[10]が100番地~109番地に割り当てられたとする.
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
D-40
配列とアドレス(ポインタ)
char ch[10]; char *p;
p = ch;
pが100番地なので,
「100番地の内容」を
*p = 1;
"1"にする.
つまり,ch[0]が
"1"になる.
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
1
D-41
配列とアドレス(ポインタ)
char ch[10]; char *p;
p = ch;
pの値は「100番地」だった.
*p = 1;
pが1増えて,
「101番地」になる.
p++;
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
1
D-42
配列とアドレス(ポインタ)
char ch[10]; char *p;
p = ch;
pの値は「101番地」.
101番地の中身が
*p = 1;
"2"になる.
すなわちch[1]が
p++;
"2"になる.
*p = 2;
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
1
2
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
D-43
配列とアドレス(ポインタ)
char ch[10]; char *p;
p = ch;
pはch[0]を指している.
*p = 1;
p++;
pはch[1]を指している.
*p = 2;
ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9]
100
番地
101
番地
1
2
102
番地
103
番地
104
番地
105
番地
106
番地
107
番地
108
番地
109
番地
D-44
ポインタ演算
int i[10]; int *p;
p = i;
printf("%p\n", p);
p++;
printf("%p\n", p);
i[0]
84
番地
85
番地
86
番地
実行結果
0013FF74
0013FF78
差が4
i[1]
87
番地
88
番地
89
番地
90
番地
i[2]
91
番地
92
番地
93
番地
94
番地
95
番地
D-45
ポインタ演算
• int型変数のアドレスに1足すと,
4バイト分増加して,次のintのアドレスになる.
– 減算も同様.
• char型変数のアドレスを1足すと,
1バイト分増加して,次のcharのアドレスになる.
– ただし, int型が4バイトとは限らない.
処理系による.ほとんどの例で4バイト.
char型は必ず1バイト.
D-46
ポインタ演算
p++を行うと,
char *p; の場合,アドレスが1番地進む.
int *p; の場合,アドレスが4番地進む.
double *p の場合,アドレスが8番地進む.
(ただし,int型が4バイト,double型が8バイトの
場合)
D-47
ポインタ演算
• 以下の様な操作が可能.
– アドレスに整数を加算/減算して,次の/前のアドレス
に格納されているデータにアクセス.
– アドレス同士の引き算をし,何個離れているか調べる
• 以下の様な操作は行えない.
– アドレスに乗算/除算を行う.
– アドレス同士の加算.
D-48
ポインタ演算 (OK)
char *p, *q; int i; の場合,
p++;
p--;
p=q+2;
p=q-2;
OK.
OK.
OK.
OK.
pのアドレスが1番地増える.
pのアドレスが1番地減る.
pはqの2番地後.
pはqの2番地前.
i=p-q; OK. iにはpとqの差が代入される.
D-49
ポインタ演算 (NG)
char *p, *q, *r; の場合,
p=q+r;
p=q*2;
p=q/2;
p=q+1.2;
NG.アドレス同士の加算はNG.
NG.アドレスに乗算と除算はNG.
NG.アドレスに乗算と除算はNG.
NG.加算減算は整数のみ.
D-50
*演算子 と []
int *p, x[10];
p = x; のとき
p
と &(x[0]) と x
は同義.
p+1 と &(x[1]) と x+1 は同義.
p+2 と &(x[2]) と x+2 は同義.
D-51
*演算子 と []
int *p, x[10];
p = x; のとき
*p
と x[0] と *x
は同義.
*(p+1) と x[1] と *(x+1) は同義.
*(p+2) と x[2] と *(x+2) は同義.
D-52
注意
int *p, x[10];
p = x; のとき
p++;
x++;
←これはOK.
←これはNG.
x という変数があるわけではない.
x は &(x[0]) という定数.
よって,読めるが書けない.
D-53
関数の仮引数と実引数(値渡し)
void func(int a){
a = 7;
}
x
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
100
番地
3
D-54
関数の仮引数と実引数(値渡し)
void func(int a){
a = 7;
}
x
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
100
番地
3
D-55
関数の仮引数と実引数(値渡し)
void func(int a){
a = 7;
}
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
x
a
100
番地
104
番地
3
3
別のメモリに割り当てられた
別の変数
D-56
関数の仮引数と実引数(値渡し)
void func(int a){
a = 7;
}
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
x
a
100
番地
104
番地
3
7
別のメモリに割り当てられた
別の変数
D-57
関数の仮引数と実引数(値渡し)
void func(int a){
a = 7;
}
x
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
実行結果
3
100
番地
3
D-58
関数の仮引数と実引数(値渡し)
void func(int x){
x = 7;
}
void main(){
int x = 3;
func(x);
printf("%d\n", x);
}
実行結果
3
この2個を
同じ名前にしても
結果は変わらない.
x
x
100
番地
104
番地
3
3
別のメモリに割り当てられた
別の変数
D-59
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
x
px
100
番地
104
番地
3
D-60
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
x
px
100
番地
104
番地
3
100
番地
D-61
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
x
px
100
番地
104
番地
3
100
番地
D-62
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
x
px
p
100
番地
104
番地
108
番地
3
100 100
番地 番地
D-63
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
x
px
p
100
番地
104
番地
108
番地
7
100 100
番地 番地
D-64
関数の仮引数と実引数(参照渡し)
void func(int *p){
*p = 7;
}
void main(){
int x = 3; int *px;
px = &x;
func(px);
printf("%d\n", x);
}
実行結果
7
x
px
100
番地
104
番地
7
100
番地
D-65
void main(){
練習0
int i, *j, k;
i = 3;
j = &i;
k = i;
*j = 4;
k = 5;
printf("i=%d\n", i);
}
D-66
void main(){
練習1
int i[2], *j;
i[0]=3; i[1]=7;
j=i;
j++;
printf("%d\n", *j);
}
D-67
void main(){
練習2
int i[2], *j;
i[0]=3; i[1]=7;
j=i;
(*j)++;
printf("%d\n", *j);
}
D-68
やってはいけないこと
void main(){
int i=0, j[2];
j[0] = 7; j[1] = 8; /* OK! */
j[2] = 9;
/* NG! */
printf("%d\n", i);
}
実行結果 9
j[0]
84
番地
85
番地
86
番地
7
j[1]
87
番地
88
番地
89
番地
90
番地
8
i
91
番地
92
番地
93
番地
94
番地
95
番地
9
D-69
やってはいけないこと
void main(){
int i[2], *p;
p = i;
/* OK. pはi[0]のアドレス */
*p = 7; /* OK. i[0] が 7 になる */
p++;
/* OK. pはi[1]のアドレス */
*p = 8; /* OK. i[1] が 8 になる */
p++;
/* NG.pはi[2]のアドレス? */
*p = 9; /* NG! i[2]相当の場所に
書き込みをしてしまう! */
}
D-70
ポインタへのポインタ
int i, *p, **pp;
iは int(整数)を入れる箱.
pは 「intの箱のアドレス」を入れる箱.
ppは「『アドレスを入れる箱』のアドレス」を入れる箱.
i
84
番地
85
番地
p
86
番地
87
番地
88
番地
89
番地
pp
90
番地
91
番地
92
番地
93
番地
94
番地
95
番地
D-71
ポインタへのポインタ
int i, *p, **pp;
i = 3;
i
84
番地
85
番地
p
86
番地
87
番地
88
番地
89
番地
pp
90
番地
91
番地
92
番地
93
番地
94
番地
95
番地
3
D-72
ポインタへのポインタ
int i, *p, **pp;
i = 3;
p = &i;
i
84
番地
85
番地
p
86
番地
3
87
番地
88
番地
89
番地
pp
90
番地
91
番地
92
番地
93
番地
94
番地
95
番地
84番地
D-73
ポインタへのポインタ
int i, *p, **pp;
i = 3;
p = &i;
pp = &p;
i
84
番地
85
番地
p
86
番地
3
87
番地
88
番地
89
番地
pp
90
番地
84番地
91
番地
92
番地
93
番地
94
番地
95
番地
88番地
D-74
ポインタへのポインタ
int i, *p, **pp;
i = 3;
p = &i;
pp = &p;
printf("%d\n", **pp);
i
84
番地
85
番地
p
86
番地
3
実行結果
3
87
番地
88
番地
89
番地
pp
90
番地
84番地
91
番地
92
番地
93
番地
94
番地
95
番地
88番地
D-75
ポインタへのポインタ
int i, *p, **pp;
i = 3;
p = &i;
pp = &p;
printf("%d\n", **pp);
i
84
番地
85
番地
*(*pp) は
*(84番地) なので,
「84番地の中身」となり
"3"を意味する.
p
86
番地
3
*pは「88番地の中身」
なので,
「84番地」を意味する.
87
番地
88
番地
89
番地
pp
90
番地
84番地
91
番地
92
番地
93
番地
94
番地
95
番地
88番地
D-76
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
*pc = n*n*n;
squareが100番地,
}
cubeが104番地で
void main(){
あったとする.
int square, cube;
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
D-77
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
*pc = n*n*n;
引数を
3,100番地,104番地
}
として,関数にジャンプ.
void main(){
int square, cube;
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
squareが100番地,cubeが104番地であったとする.
D-78
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
nが3,
*pc = n*n*n;
psが100番地,
pcが104番地として
}
関数sq_cuを開始.
void main(){
int square, cube;
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
squareが100番地,cubeが104番地であったとする.
D-79
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
psは"100番地".
「100番地の中身を
*pc = n*n*n;
3*3にする」
}
という処理.
これにより
void main(){
squareの値が
int square, cube;
変わる.
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
squareが100番地,cubeが104番地であったとする.
D-80
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
pqは"104番地".
「104番地の中身を
*pc = n*n*n;
3*3*3にする」
}
という処理.
これにより
void main(){
cubeの値が
int square, cube;
変わる.
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
squareが100番地,cubeが104番地であったとする.
D-81
応用例:値を2個返す関数
C言語では,戻り値は1個しか用意できない.
void sq_cu(int n, int *ps, int *pc){
*ps = n*n;
実行結果
*pc = n*n*n;
9 27
}
void main(){
int square, cube;
sq_cu(3, &square, &cube);
printf("%d %d\n", square, cube);
}
squareが100番地,cubeが104番地であったとする.
D-82
多次元配列の配置
• int a[3][2]は,
「長さ2の配列」が3本であって,
「長さ3の配列」が2本ではない?
int a[3][2]は以下の順で割り当てられる.
a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1]
D-83
復習
i
void main(){
int i=10, j=11;
104番地
int *p;
の中身
p=&j;
printf("*p=%d\n",*p);
*p=7;
printf("i=%d j=%d",i,j);
} 104番地
の中身
j
p
100 104 108
番地 番地 番地
10
11
10
11
10
11 104
10
11 104
10
7
104
10
7
104
*p=11
実行結果 i=10 j=7
D-84
練習 3
void main(){
int x=10, y=11, z=12;
int *p;
printf("x=%d y=%d z=%d\n",x,y,z);
p=&x;
*p=5;
printf("x=%d y=%d z=%d\n",x,y,z);
p=&y;
*p=6;
printf("x=%d y=%d z=%d\n",x,y,z);
p=&z;
*p=7;
printf("x=%d y=%d z=%d\n",x,y,z);
}
何と表示される?
D-85
解答 3
x=10 y=11 z=12
x=5 y=11 z=12
x=5 y=6 z=12
x=5 y=6 z=7
D-86
練習 4
void main(){
何と表示される?
int x[3];
int *p;
x[0]=10; x[1]=20; x[2]=30;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
p=x;
/* p=&(x[0]) の意味 */
*p=7;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
p++;
*p=6;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
p++;
*p=5;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
}
D-87
解答 4
x[0]=10 x[1]=20 x[2]=30
x[0]=7 x[1]=20 x[2]=30
x[0]=7 x[1]=6 x[2]=30
x[0]=7 x[1]=6 x[2]=5
D-88
練習 5
void main(){
何と表示される?
int x[3];
int *p;
x[0]=10; x[1]=20; x[2]=30;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
p=x;
/* p=&(x[0]) の意味 */
*p=7;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
(*p)++;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
*p=6;
printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]);
}
D-89
解答 5
x[0]=10 x[1]=20 x[2]=30
x[0]=7 x[1]=20 x[2]=30
x[0]=8 x[1]=20 x[2]=30
x[0]=6 x[1]=20 x[2]=30
D-90