プログ

’14修了無内定理系院卒の活動雑記||プー太郎ログ||プログラミング雑記

未だにポインタが怪しい奴が居るらしい

本番はもう来週だってのにやっとこさ午後問に挑戦しました.とりあえず平成24年秋を解いたんだけど,解答はあっても配点はないから正しい点数がわからないという.とりあえず自分で配点したら82点だったので足りてるけど,例のごとく自信あった問題だけで60点越えてるかというと怪しい.受けてみた感想としては,午前に比べて大分時間が無いように感じた.具体的には必答489を答えた上で,12567と解いて行って7の真ん中くらいでタイムアップ.つまり「大問を1つ余分に解いて一番ダメそうなやつを切る」ってのは時間が足りなさそう.これは問題を印刷していないことに依る他ページ参照のしにくさが影響してるけど,一方でマークする時間も必要になるからプラマイ0くらいかも.それ以外で言うと,とにかく不要な情報が多いので設問を先に読んである程度必要な情報の傾向を絞るのが大事そう,現代文かよ.んでまぁ点数上げるために復習をしたいけど,午後問は解説してるサイトが全然見当たらない.本買えば良いんだろうけど,8割取れてるし自分で勉強しても間に合ってそうな気がするんだよなぁ.ただ問題は見にくいし解説はないし自分で探してもあまり自信なかったりで午前の勉強に比べて失速が半端ない.

んでタイトルのポインタだけど,ポインタは試行錯誤しながらコンパイルすることで実装してきたので,試験のように1回しか回答できないと未だに怪しい,ぶっちゃけswap関数すら1回で正答する自信がない.今回も2択に絞った上で負けました.
・H24秋期午後 9-1(a)
リスト構造の末尾まで探索するためにfor文の条件式を埋める問題.二重ポインタだから余計に分からない.答えを見ると char** list[N] の末尾まで探索するには for(i=0;list[N][i]!=NULL;i++) になってる.

とりあえずポインタのおさらい.さっき挙げたスワップ関数は,以下のとおり.

void swap(int *a, int *b){
  int c = *a;
     *a = *b;
     *b =  c;
}
void smap(int a, int b){ //ダメな例
  int c = a;
      a = b;
      b = c;
}
~略~
  int x=0, y=1;
  swap(&x, &y); //x=1,y=0に
  smap( x,  y); //変化なし
~略~

宣言時の引数*a,*bはint型のポインタ.cはint型で,*a,*bはポインタの示す値.a,b自体にはアドレスが格納されている.c=*a は,「int型変数cにポインタ*aの示すint型変数の値を代入」.*a=*b は,「ポインタ*aの示すint型変数にポインタ*bの示すint型変数の値を代入」.最後に*b=c は「ポインタ*bの示すint型変数にint型変数cの値を代入」.んで関数を呼び出す場合にはポインタを渡す必要があるので,&x,&yとしてやる.引数定義の際にポインタ型にしない場合は,値だけを利用するため元の変数には何も変化が起きず,スワップできない.1つ気になるのは,a=&x みたいな書き方をする場合.これは「ポインタ*aの指し示すアドレスを変数xのアドレスに書き換える」って処理だけど,引数として渡す場合は*aに対し&xを渡してるのにそれとズレてるんだよね.まぁ「int *a; a=&x」が省略されてなってるんだとは思うけど,この辺りにもポインタが分かりにくいと言われる所以があると思う.

つづいてchar型のポインタについて.char型が特に紛らわしいのは,元々サイズを指定するために添字が必要なので,添字が増えた時にサイズなのか配列なのか分からなくなってしまう点じゃないだろうか.とりあえず,char型からchar**までまとめる.

※前置き
N,M 定数
i,j,k 変数

・char型
ポインタでもない普通のchar型変数.
宣言:char str[N];
Nの意味:サイズ
代入:str = "STR";
探索の条件式:i<N もしくは str[i]!='\0'
備考:M文字の文字列を代入するとM+1文字目にヌル文字'\0'が代入.
M>Nの時は代入ができず,M=Nの時は代入はできるがヌル文字が入りきらないため,%sなどで表示するとバグる.

・char*型
char型のポインタ.
宣言:char* ary[N];
Nの意味:要素数,各文字列の長さは不定.
代入:ary[i] = "ARY" or str(char型) ;
探索の条件式:i<N もしくは ary[i]!=NULL 
備考:char* ary[N] = "ARY1","ARY2", ... , "ARYN";
のように宣言と同時に列挙して代入可能.
この方法でcharg型変数strを代入することもできるが,列挙の最初にある場合は中括弧{}で括る必要がある.
×)char* ary[N] = str, "STR", ... , "ARY";
◯)char* ary[N] = {str, "STR", ... , "ARY"};
◯)char* ary[N] = {"STR", str, ... , "ARY"};


・char**型
char型のポインタのポインタ
宣言:char** list[N];
Nの意味:要素数,各文字列の長さおよびchar*の要素数は不定.
代入:list[i] = ary;
探索の条件式:i<N もしくは list[i][j]!=NULL
備考:char** list[N] = {ary, ary, ... , ary};
のように宣言と同時にchar型ポインタを列挙して代入可能.文字列書くのはわからない.
list[i][j]の文字列を参照したい場合は,list[i][j],k文字目を参照したい場合は,*(list[i][j]+k-1)となる.

※一部表示が意図してないものになっていたため修正.Web上にコードライクなの書くのはいちいちめんどくさいね.

最後のはアドレス値を直接いじっていてポインタらしい印象を受ける.ただ,こういうやり方もある程度で実際に使うことは少なそうかな,分かりにくいし.「○○は△△型!」みたいに覚えるとこういう発想出てきにくそうだし,char型云々と言うよりはアドレス表現の仕方の1つと認識したほうが良さそう.