情報処理Ⅱ 2005年11月18日(金) 本日学ぶこと ポインタ(Pointer) 問題 文字列が回文("noon", "トマト" など)かどうか判定でき る? 2 ポインタ ポインタとは? 指し示すもの 配列とはまた別の,実用的かつ多様な型を作る一つの方式 (派生型) y *y なぜ必要? メモリ(特に,配列とヒープ)に効率よくアクセスできるから. 関数の仮引数によく使用されるから. 3 ポインタ変数の宣言(1) ポインタ変数の宣言 char *p; と書くと,「char *」型の変数pを確保する. • char* p; と書く流儀もある. 一括の宣言 char *p, *q; のように複数宣言できる. char *p, q; とすると,qはchar型になる. 「*」は 演算子ではなく 型名の一部 4 オブジェクトとポインタの関係(1) int x; int *y; とするとき, x はint型の変数,またはその値 y はint *型のポインタ変数,またはその値(ポインタ値) *y は「yの参照先」を表すint型の値 &x は「xの参照」を表すint *型のポインタ値 * と & は 単項演算子 (積や論理積 ではない) x &x y *y 5 オブジェクトとポインタの関係(2) int z[10]; とするとき, z[k] はint型の値(左辺値に なり得る) &z[k] および z+k は, 「z[k] の参照」を表す int *型のポインタ値 ポインタ値としては, z z と z+0 と &z[0] は 同じ値となる. 演算子の優先順位に 注意すると,&z[k]は, (&z)[k]ではなく &(z[k])と同じ 配列変数は,参照時 にはポインタとなる! z+0 z+1 z+9 z[0] z[1] … z[9] &z[0]&z[1] &z[9] 6 ポインタ変数の宣言(2) 初期化 ○ int x; int *y = &x; ○ char a[10]; char *b = a; ○ char *p = "programming"; 「初期化」と「式」とで型の違いに注意! この b は a の 別名(alias)と いう. char *b = a; ⇒ a はchar *型 char *b; *b = a; ⇒ a はchar型 7 配列とポインタ(1) int x[5]; int *y = x; とするとき, x[3] と y[3] と *(x + 3) と *(y + 3) は同じオ ブジェクトを表す. 左辺値になり得る(代入可能). 変数αが配列変数であってもポインタ変数であっても,α[i] と *(α + i) は同じオブジェクトを表す. • i は負でもよい. • *(α + 0) は *α と書ける. x[0] x[1] x[2] x[3] x[4] y[0] y[1] y[2] y[3] y[4] x y 8 配列とポインタ(2) int x[5]; int *y = x + 1; とするとき, x[3] と y[2] は同じオブジェクトを表す. x[0] x[1] x[2] x[3] x[4] y[-1] y[0] y[1] y[2] y[3] x y z (同一型の)ポインタ同士の減算が可能. 上図で,y – x は 1. y – z は -3. 同一配列を参照している2つのポインタがどれだけ離れている かを知ることができる. 9 同じオブジェクト? ポインタ値は,printf関数の第1引数に「%p」を使用すれば 出力できる. 注意 2つのポインタ値が同じオブジェクトを指すことがあっても,そ れらが同じ型かどうかはわからない. • キャスト演算子でポインタ型の変換が可能. • 実行時に型名を獲得する方法はない. 10 ポインタ変数にできて 配列変数にできないこと (前提: int x[5]; int *y;) 代入 ○ y = x; × x = y; 整数との加減算 ○ y++; や y -= 3; × x++; や x -= 3; x x[0] x[1] x[2] x[3] x[4] y y+1 y+2 y+3 y+4 11 配列変数にできて ポインタ変数にできないこと(1) 初期化していない状態での参照や代入 int x[10]; int *y; とするとき, • ○ x[5] = 1; • × y[5] = 1; 適切に指し示す先を設定しておけば,問題ない. x y x[0] x[1] … x[9] ??? 初期化していないとき, それぞれの値は不明. しかし代入はできる. 12 配列変数にできて ポインタ変数にできないこと(2) 文字列の書換え char x[ ] = "programming"; char *y = "programming"; とするとき, • ○ x[7] = '\0'; • × y[7] = '\0'; • 配列変数 x の初期化は,文字列が配列値として格納され るのに対して,ポインタ変数 y への代入は,(書換えられ ない)文字列リテラルを参照するだけだから. • ○ y = x; y[7] = '\0'; 13 直感的には 配列変数は安定的 ポインタ変数は身軽 x x[0] x[1] x[2] x[3] x[4] y y+1 y+2 y+3 y+4 y-1 y y+1 y+2 y+3 y++; 14 回文判定 仕様 入力(文字列)は,ポインタ変数にあらかじめ参照させておく. 文字列が回文になっていれば「Yes」を,そうでなければ「No」 を出力する. 英字の大小を区別する.ASCIIコード以外の文字は使用しな い. case-sensitive という 例 "12321" : Yes "123321" : Yes "noon" : Yes "Noon" : No 15 回文判定 1文字ずつ見ていく操作を 文字列の「走査(scan)」という 左と右から1文字ずつ見て 途中で一致していない箇所があれば,「No」 すべて一致し,参照位置が一致または交差すれば,「Yes」 '1' p '2' '3' '4' q '1' '1' '\0' No '\0' Yes r '2' '3' '2' '1' 16 回文判定:ポインタ変数は? char *p = "12321"; char *q = p; 文字列走査では固定 文字列の先頭から始まる 文字列走査により1ずつ増えていく char *r; 文字列の末尾から始まる 文字列走査により1ずつ減っていく 17
© Copyright 2025 ExpyDoc