プログラミング演習 II 講義資料 3 ポインタ I - ポインタの基礎 1 ポインタとは ポインタとはポインタは, アドレス ( データが格納されている場所 ) を扱うデータ型です つまり, アドレスを通してデータを間接的に処理します ポインタを使用する場合の, 処理の手順は以下のようになります 1 ポインタ変数を宣言する 2 ポインタ変数へアドレスを割り当てる 3 ポインタ変数を用いて処理 ( 演算 ) を行う 4 結果を表示する 1.1 ポインタ変数を宣言する す ポインタ変数を使用する場合, 一般の変数と同様に使用に先立って, その宣言を行いま ポインタ変数の宣言の仕方ポインタ変数の宣言の仕方は, これまでの変数の場合と少し異なります ポインタ変数は, データの記憶されているアドレスを参照するためのもので, 参照するデータの種類によって次のように宣言します 参照するデータ型 * ポインタ変数 例えば, 以下のようになります (pi,pf,pd,pc がポインタ変数名 ) 参照するデータがint 型 ( 整数 ) の場合 : int *pi ; 参照するデータが float 型 ( 小数点の付いた数 ) の場合 : float *pf ; 参照するデータが double 型 ( 小数点の付いた数 ) の場合 :double *pd ; 参照するデータが char 型 ( 文字 ) の場合 : char *pc ; ( 文字列を扱う場合も, 同様 ) ポインタ変数の宣言は, ポインタ変数のデータ型を示すものではなくそのポインタ変数で参照できるデータの型を示すものです ポインタ変数を使う場合には, その変数が何型のデータを指しているかを常に念頭におく必要があります プログラミング演習 II 3-1
1.2 ポインタ変数へアドレスを割り当てるポインタ変数は, 宣言しただけではどの場所 ( アドレス ) も指し示していないので, 操作するデータを指し示すようにポインタ変数にデータのアドレスを代入しておかなければなりません 例えば,int 型のデータの格納されている変数 n をポインタ変数 pn によって扱うときには, 変数 n のアドレスを変数 pn に代入します そこで, 変数のアドレスを求めるための演算 & が用意されています &n は変数 n のアドレスを表します (scanf を用いてキーボードからデータを入力するとき, データの格納場所を &n のように指定したのは, そのアドレスを指定するためです ) プログラムで書くと以下のようになります int n ; /* n はint 型データ ( 整数 ) */ int *pn ; /* pn はint 型データへのポインタ変数 */ pn=&n ; /* 変数 n のアドレスを代入 */ ポインタ変数を宣言しただけ 変数 n のアドレスを代入 pn? pn n n のアドレス 1.3 ポインタ変数を用いて処理 ( 演算 ) を行う 演算子 * ポインタ変数の値はアドレスですから, データの内容を扱うことはできません そこで, データの内容を扱うために, アドレスをもとにその中身を表す演算子 * が用意されています 前述の例では,*pn の値はn となります 従って, *(&n ) == n という関係が成り立ちます ポインタ変数と演算ポインタ変数には, 加算, 減算, インクリメント (+1), デクリメント (-1), 関係演算, 論理演算を行うことができます 演算の結果は, ポインタが指す変数などの型のサイズに依存します 例えば, ポインタ変数 pi が int 型 (4 バイト ) のデータを指すポインタ変数であるとき, pi + n (n は整数 ) プログラミング演習 II 3-2
という演算を行うと, 結果は pi + 4 n という値になります すなわち,+1 するごとに その指し示す変数 ( データ ) のサイズ ( バイト数 ) 分単位で変化します これは,+1 する とそのサイズに関係なく次のデータを指し示すように値が変化することを意味します ポインタを用いたプログラム例 int a, b, x ; int *c, *d=&b, *y; *c = 10; *d = 20; *y = *c + *d; printf("a=%d b=%d a+b=%d n", a, b, x) ; c = &a; y = &x; return 0 ; ポインタの演算の例 double a; double *pa; pa = &a; printf("pa=%x n", pa); pa = pa + 1; printf("pa=%x n", pa); pa = pa + 1; printf("pa=%x n", pa); return 0; プログラミング演習 II 3-3
char a; int n; double x,y; char *pa; int *pn; double *px,*py; pa = &a; pn = &n; px = &x, py = &y; printf("pa: %x n", pa); pa = pa + 2 ; printf("pa = pa + 2 n"); printf("pa: %x n", pa); printf("pn: %x n", pn); pn = pn - 2 ; printf("pn = pn - 2 n"); printf("pn: %x n", pn); printf("px: %x n", px); px = px++; printf("px++ n"); printf("px: %x n", px); printf("py: %x n", py); py--; printf("py- printf("py: %x n", py); return 0; 演算前 pa = 0x0DF0 pn = 0x0DF4 px = 0x0E00 py = 0x0E08 とすると, 演算後の値は pa = pn = px = py = プログラミング演習 II 3-4
2 ポインタと文字列 ポインタ変数への文字列の代入文字列を扱うには配列を用いました 配列では, 例えば static char a [] = Hello ; のように, 文字列で初期化を行うことができました しかし, 初期化以外で配列に文字列を代入するということは出来ませんでした 配列に文字列をセットするには繰り返しを用いて一文字ずつ行わなければなりません 文字型へのポインタ変数には, 次のように文字列を代入することが出来ます char *str ; str = Hello ; これは, 実際には, Hello という文字列がメモリのあ る場所に格納され, その先頭のアドレスをstr という変数 が指している ( すなわち, 先頭のアドレスの値がstr にセ ットされる ) ことを意味します Hello という文字列は, int n; メモリのある番地から順に, int *i; H, e, l, l, o, 0 i = &n; と連続して格納されます *i = 10; 従って,*(str+4) の値は o となります printf("%d\n", n); この, Hello という文字列を表示するには return 0; printf( %s n, str) ; とします プログラミング演習 II 3-5
課題 3_1 入力した整数が偶数ならば 偶数 (even number) を奇数ならば 奇数 (odd number) を表示するプログラムをポインタ変数を用いて作成 [ プログラムの説明 ] (1) プログラムで必要な変数やポインタの型を宣言する (2) キーボードから整数を変数 a に入力する (3) 変数 a の内容が偶数か奇数かを判別する (4) 入力された整数が偶数か奇数かを表示する [ プログラム ] #include stdio.h int a ; int *b ; scanf( %d, &a) ; if( ア ) イ ; else ウ ; printf( 入力されたデータは %s です n, b ) ; return 0 ; 課題 3_2 ポインタ変数を用いて, 自分の名前をポインタ変数に代入して, 名前をそのまま表示す る 次に, 名前を逆順に表示するプログラムを作成しなさい /////////////// 前回の課題のプログラム例 課題 2_2 /* program2_2 */ #include<stdio.h> int i,p ; static char season[4][7] = "spring", "summer", プログラミング演習 II 3-6
"autumn", "winter" ; char input[3] ; printf(" 季節を表す英語のスペルのうちどれか最初の 2 文字を入力して下さい \n"); scanf("%s",input); p=0; for(i=0; i<=3; i++) if(input[0]==season[i][0] && input[1]==season[i][1]) printf("%s\n",season[i]); p=1 ; break ; /* 一致するものが見つかったらそれ以上処理を行わない */ if(p==0) printf("not found\n"); return 0 ; プログラミング演習 II 3-7