第11章 ポインタ1

情報処理演習
第7回
11月12日
工学部6・7・8・9・10組
学籍番号末尾偶数
1
東北大学 大学院情報科学研究科
全 眞嬉
http://www.dais.is.tohoku.ac.jp/~jinhee/enshu-15.html
2
ポインタ
1.ポインタの基礎
→本日
2.数値データのポインタ →本日
3.文字データのポインタ →次回
メモリとアドレス
3

変数と配列
 値を格納する方法について学んだ
 格納した値は必要に応じてプログラムの中でいつで
も呼び出し可能
 格納された値はメモリに保存される

メモリ
 コンピュータ上で数値や文字などの値を保存して置く
装置

アドレス
 メモリ上でどこに保存されているかを示す住所
変数に値を格納する
4
50
75
a[0][0]
a[0][1]
a[1][0]
a[1][1]
100
x
25
3
変数に値を格納する
=
ロッカーに荷物を入れる
ロッカーに荷物を入れる
5

ロッカーに荷物を入れる手順
 空いているロッカーを探す
 荷物を入れてカギを掛ける
 ロッカーの番号を覚える

ロッカーから荷物を取り出す手順
 番号でロッカーを探す
 カギで開けて荷物を取り出す
ロッカー番号=メモリアドレス
6

ロッカーの番号は大切
 効率的
 番号が無ければ大量のロッカーから荷物を探すのは
大変

コンピュータでも同様
 大量のデータが保存されているメモリから何の手が
かりなしで必要な情報を取り出すのはできない
 アドレスを用いる
ロッカー
コンピュータ
番号
アドレス
メモリに変数の値を格納する
7


値が格納される場所
アドレス番号が必要
メモリ
変数x
x
100
データ型名
サイズ
char
1バイト
short
2バイト
int、 long
4バイト
float
4バイト
double
8バイト
格納される場所
4バイト
変数のアドレス
8

メモリ上の何番のアド
レスに変数が格納され
ているか
 アドレス番号を気にす
る必要は無い


変数のアドレスを確認
&変数名
アドレスを表示させる
変換指定子
 %p
/*ex22.c*/
#include<stdio.h>
main()
{
int x=100;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
}
変数のアドレス
9
int x=100;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
実行結果
x=100
address : ffbffc1c

変数xの値とメモリ上の
何番地に格納しているか
を確認
 ffbffc1c
 16進数
 1バイト
変数のサイズを確認(sizeof演算子)
10
int x=100;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
printf("size : %d byte¥n",sizeof(x));
実行結果
x=100
address : ffbffc1c
size : 4byte

データ型名
サイズ
char
1バイト
short
2バイト
int、 long
4バイト
float
4バイト
double
8バイト
sizeof 演算子
型や変数のバイト数を調べられる
 sizeof(変数名)

sizeof(x)

sizeof(型)
sizeof(int)
sizeof(double)
変数のアドレス
11


変数の値を変更し、
アドレスを確認
ex22.c を変更
 xの値を200に変更
するプログラム

値を変更しても変数
のアドレスは変わら
ない
/*ex22.c*/
#include<stdio.h>
main()
{
int x=100;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
printf("size : %d byte¥n",sizeof(x));
x=200;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
printf("size : %d byte¥n",sizeof(x));
}
変数のアドレス
12
int x=100;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
printf("size : %d byte¥n",sizeof(x));
x=200;
printf("x = %d¥n",x);
printf("address : %p¥n",&x);
printf("size : %d byte¥n",sizeof(x));

実行結果
x=100
address : ffbffc1c
size : 4byte
x=200
address : ffbffc1c
size : 4byte
値を変更しても変数xのメモリ上の格納場所
であるアドレスは変わらない
 格納される値のみ変更される
配列のアドレス
13
実行結果
a[0]= 100,
a[1]= 34,
a[2]= 78,
a[3]= 45,
a[4]= 98,
a[5]= 56,
a[6]= 100,
a[7]= 89,
a[8]= 94,
a[9]= 78,
address : ffbffbf4
address : ffbffbf8
address : ffbffbfc
address : ffbffc00
address : ffbffc04
address : ffbffc08
address : ffbffc0c
address : ffbffc10
address : ffbffc14
address : ffbffc18
/*ex23.c*/
#include<stdio.h>
main()
{
int i;
int a[10]={100,34,78,45,98,56,100,89,94,78};
for(i=0;i<10;++i)
printf(“a[%d]=%3d, address : %p¥n”,i,a[i],&a[i]);
}
配列におけるメモリ上のアドレス
14
メモリ
a[0]= 100, address : ffbffbf4
a[1]= 34, address : ffbffbf8
a[2]= 78, address : ffbffbfc
a[3]= 45, address : ffbffc00
a[4]= 98, address : ffbffc04
a[5]= 56, address : ffbffc08
a[6]= 100, address : ffbffc0c
a[7]= 89, address : ffbffc10
a[8]= 94, address : ffbffc14
a[9]= 78, address : ffbffc18
データ型名
サイズ
char
1バイト
short
2バイト
int、 long
4バイト
float
4バイト
double
8バイト
a[0] a[1] a[2] a[3] a[4] a[5] a[6] ・・・・
4byte 4byte 4byte 4byte 4byte 4byte 4byte
ポインタとは
15



変数の一種
アドレスを格納するための変数
ポインタと言う特殊の変数を用いることで、他の変
数たちが持つアドレスを格納することが可能
100
x
変数xの
アドレス
ffbffc1c
ポインタ
アドレスを格納できる変数
ポインタの変数の宣言
16

宣言方法
 他の変数と同様ポインタ変数の宣言を行う
 変数の名前の前に「*」を付ける
 型名
*変数名;
int *p1;
float *p2;
char *p3;
 宣言により変数
p1,p2,p3のポインタ変数が用意される
 「*」はポインタ宣言時には付けるが、ポインタ名には「*」
を付けないので注意
ポインタの宣言と変数の宣言
17

ポインタ変数を宣言する際には必ず「*」を付ける
ポインタの宣言
int *a;
int b;
変数の宣言
ポインタの変数の宣言
18

ポインタを宣言する際に変数の型名を
指定
 int型ポインタ、int*型
int *p1;
 float型ポインタ、flaot*型
float *p2;
char *p3;
 char型ポインタ、char*型
ポインタの型
19

変数のアドレスはその
変数の型に対応した
ポインタ変数にしか格
納できない
 int型のポインタであるint*
型のポインタ変数のみに
そのアドレスの格納可能
100
int 型
x
ffbffc1c
○
int *型
変数xの
アドレス
×
float*型
ポインタを使うメリット
20

C言語でポインタを用いると
 関数などで変数のアドレスを引数として渡すことがで
きる
 文字列や配列をより便利に利用できる
 その他の型を含めた動的なデータ構造を定義できる
ポインタへのアドレス代入
21
/*ex24.c*/
#include<stdio.h>
main()
{
int x;
int *p;
p=&x;
printf("address of x : %p¥n",&x);
printf("pointer p : %p¥n",p);
}
実行結果
address of x : ffbffc18
pointer p : ffbffc18

普通の変数か
ポインタ変数か
によって記述す
べき内容が異
なる
&x はxのアドレ
ス、&演算子を
利用した計算式
 p はxのアドレス
を格納している
ポインタ変数

ポインタから変数の値を参照
22


ポインタに格納されているアドレスから、そこに格納
されている変数の値を取得
間接参照演算子 *
*ポインタ変数名;
 ポインタ側からある変数に格納されている値を調べる

ex24.c を変更
 下記を追加
x=100;
printf(“value of x : %d¥n",x);
printf("value of p : %d¥n",*p);
実行結果
address of x : ffbffc18
pointer p : ffbffc18
value of x : 100
value of p : 100
&演算子と*演算子と各変数の対応
23

&演算子


変数が格納されているアドレスを返す演算子
*演算子

ポインタからそのアドレスに格納されている値を返す演算子
/*ex24.c*/
#include<stdio.h>
main()
{
int x;
int *p;
p=&x;
printf("address of x : %p¥n",&x);
printf("pointer p : %p¥n",p);
x=100;
printf(“value of x : %d¥n",x);
printf("value of p : %d¥n",*p);
}
x
変数xの値
&x 変数xが格納されているア
ドレス
p
変数xのアドレスが格納さ
れているポインタ
&xのアドレス
と同じ
*p ポインタpが指すアドレスに xの値と同じ
格納されている変数の値
配列要素とアドレス
24
b[0]= 36.5
b[1]=38.4
b[2]=37.5
メモリ
b[0] b[1] b[2]
4byte 4byte 4byte
データ型名
サイズ
char
1バイト
short
2バイト
int、 long
4バイト
float
4バイト
double
8バイト
配列要素とアドレス
25

配列でのアドレス

配列の要素の前に&を付けると値が格納されているアドレ
スが分かる


配列名の演算によって各配列要素のアドレスを取得でき
る


&b[0],&b[1],&b[2]
b+1,b+2
配列のアドレスを求める方法
&を使う方法
配列名で指定する方法
&b[0]
&b[1]
&b[2]
b
b+1
b+2
b[0]= 36.5
b[1]=38.4
b[2]=37.5
配列要素とアドレス
26
/*ex25.c*/
#include<stdio.h>
main()
{
float b[3]={36.5, 38.4, 37.5};
printf("address of b[0]: %p, b : %p¥n",&b[0], b);
printf("address of b[1]: %p, (b+1): %p¥n",&b[1], (b+1));
printf("address of b[2]: %p, (b+2): %p¥n",&b[2], (b+2));
}
実行結果
address of b[0]: ffbffc14, b
: ffbffc14
address of b[1]: ffbffc18, (b+1): ffbffc18
address of b[2]: ffbffc1c, (b+2): ffbffc1c
配列のアドレスから値を調べる
27


変数の場合と同様に配列要素に関してもアドレス
情報から格納されている値を取得可能
間接演算子*を利用
*b
*(b+1)
*(b+2)
 注意
 0番地以外は()を忘れずに付ける
 *(b+1)
 *b+1
配列のアドレスから各配列要素の値を参照
28
/*ex26.c*/
#include<stdio.h>
main()
{
int i;
float b[3]={36.5, 38.4, 37.5};
for(i=0;i<3;++i)
printf("value of b[%d]: %3.1f, value of *(b+%d): %3.1f¥n",i,b[i],i, *(b+i));
}
実行結果
value of b[0]: 36.5, value of *(b+0): 36.5
value of b[1]: 38.4, value of *(b+1): 38.4
value of b[2]: 37.5, value of *(b+2): 37.5
配列における記述法の比較(先頭要素の場合)
29
配列要素での指定
値
b[0]
アドレス &b[0]



配列名での指定
*b
b
ポインタはアドレスを指し示すための変数
配列bに関してはbと記述することで配列が確保してい
るメモリの中の先頭のアドレスを取得できる
つまり、bは配列の先頭要素のアドレスが格納されてい
るポインタ変数でもある
演習1
30
/*ex27.c*/
/*学籍番号:
名前:
*/
/*ポインタが指す変数の値の表示*/
#include<stdio.h>
main()
{
int i=10;
int *p;
/*int型変数を指すポインタpの宣言*/
p=&i;
/*ポインタpに変数iのアドレスを代入*/
printf("%d ¥n",*p);
/*ポインタpの指す変数の値を表示*/
*p=10*(*p);
/*ポインタpの指す変数の値を10倍にする*/
printf("%d ¥n",*p);
/*ポインタpの指す変数の値を表示*/
}
実行結果
10
100
演習2
31
/*ex28.c*/
/*学籍番号:
名前:
*/
/*ポインタが指す変数の計算*/
#include<stdio.h>
main()
{
int a=10;
int b=5;
int c;
int *pa ;
/*aへのポインタpaを宣言*/
int *pb ;
/*bへのポインタpbを宣言*/
pa= &a ;
/*アドレス演算子によりaのアドレスをpaに代入*/
pb= &b ;
/*アドレス演算子によりbのアドレスをpbに代入*/
c=*pa + *pb;
printf("a+b=%d¥n",c);
}
実行結果
a+b=15