ホーム » 2018 » 9月

月別アーカイブ: 9月 2018

2018年9月
 1
2345678
9101112131415
16171819202122
23242526272829
30  

検索・リンク

ポインタと番地の理解

リスト構造とかのプログラミングでは、ポインタが使われるが、番地とポインタをうまく理解していないと、どのような処理をしているのか理解しづらいはず。

今回の補講では、ポインタを理解してもらう。

以下では、ポインタを使った処理(前半)を見て、ポインタの動きを考える。理解できていなければ、同じ処理をポインタ無し、番地を意識させる memory[] 配列による記述(後半)で、動きを追って2つのプログラムが同じ挙動を表している…という説明の繰り返しで、ポインタの理解を図る。

単純な変数の加算

プログラムで、「 c = a + b ; 」と書いてあったら、メモリの「変数aの番地の中身」と「変数bの番地の中身」を加えて、結果を「変数cの番地」に保存する。

// 変数 a と 変数b の加算
int a = 11 ;
int b = 22 ;
int c ;
c = a + b ;
// 同じ処理をメモリの番地のイメージを示す。
int memory[ 1000 ] = { 0 , 0 , 0 , 11 , 22 , 0 , 0 } ;
#define ADDR_A 3
#define ADDR_B 4
#define ADDR_C 5
memory[ ADDR_C ] = memory[ ADDR_A ] + memory[ ADDR_B ] ;

ポインタのイメージ

// ポインタの処理
int a = 11 ;
int b = 22 ;
int*p ;
p = &a ;
(*p)++ ;
p = &b ;
(*p)++ ;
// 同じ処理をメモリ番地のイメージで
int memory[ 1000 ] = { 0 , 0 , 0 , 11 , 22 , 0 , 0 } ;
#define ADDR_A 3
#define ADDR_B 4
int p ;              // int *p ;
p = ADDR_A ;         // p = &a ;
memory[ p ]++ ;      // (*p)++ ;
p = ADDR_B ;         // p = &b ;
memory[ p ]++ ;      // (*p)++ ;

ポインタ渡し

// ポインタ引数による値の交換
void swap( int*x , int*y ) {
   int tmp = *x ;
   *x = *y ;
   *y = tmp ;
}
void main() {
   int a = 11 ;
   int b = 22 ;
   swap( &a , &b ) ;
}
// 同じ処理をメモリ番地のイメージで。
int memory[ 1000 ] = { 0 , 0 , 0 , 11 , 22 , 0 , 0 } ;
#define ADDR_A 3
#define ADDR_B 4
void swap( int x , int y ) {    // void swap( int*x , int*y ) {
   int tmp = memory[ x ] ;      //   int tmp = (*x) ;
   memory[ x ] = memory[ y ] ;  //   (*x) = (*y) ;
   memory[ y ] = tmp ;          //   (*y) = tmp ;
}                               // }
void main() {
   swap( ADDR_A , ADDR_B ) ;    // swap( &a , &b ) ;
}

上記のポインタの説明では、番地をintで表現しているから、型の概念が曖昧になりそう。
本当は、以下のように pointer 型を使って説明したいけど、補講の学生に typedef は、混乱の元だろうな。ひとまず、ここまでのポインタのイメージを再学習するネタを見てもらってからなら、typedef int pointer してもいいかな?

typedef int pointer ;
void swap( pointer x , pointer y ) {
   int tmp = memory[ x ] ;
   memory[ x ] = memory[ y ] ;
   memory[ y ] = tmp ;
}

プログラミングでは、型の理解が重要。たとえ、Python,Ruby といった型宣言の無い言語でも、どんなデータなのかを意識して書く必要がある。

理解の確認

// 以下のプログラムの実行結果は?
void foo( int x ) {
   x++ ;
}
void bar( int*p ) {
   (*p)++ ;
}
void main() {
   int a = 111 ;
   foo( a ) ;  // a の中身は?
   bar( &a ) ; // a の中身は?
}
// 同じ処理を
typedef int pointer ;
int memory[ 1000 ] = { 0 , 0 , 0 , 111 , 0 , 0 } ;
#define ADDR_A 3
void foo( int x ) {
   _______________________ ;
}
void bar( pointer p ) {
   _______________________ ;
}
void main() {
   foo( ________________ ) ; // memory[ ADDR_A ] の中身は?
   bar( ________________ ) ;  // memory[ ADDR_A ] の中身は?
}

ポインタと配列

// ポインタの移動
int sum = 0 ;
int array[ 3 ] = { 11 , 22 , 33 } ;
int*p ;
p = array ;
sum += *p ;
p++ ;
sum += *p ;
p++ ;
sum += *p ;
// 同じ処理をメモリ番地のイメージで
typedef int pointer ;
int memory[ 1000 ] = { 0 , 0 , 0 , 11 , 22 , 33 , 0 , 0 } ;
#define ADDR_SUM 2
#define ARRAY 3
pointer p ;                          // int*p ;
p = ARRAY ;                          // p = array ;
memory[ ADDR_SUM ] += memory[ p ] ;  // sum += (*p) ;
p++ ;                                // p++ ;
memory[ ADDR_SUM ] += memory[ p ] ;  // sum += (*p) ;
p++ ;                                // p++ ;
memory[ ADDR_SUM ] += memory[ p ] ;  // sum += (*p) ;

理解の確認

整数配列にデータが並んでいる。数字は0以上の数字で、データ列の後ろには必ず0が入っているものとする。配列の先頭から0を見つけるまでの値を合計する関数を作れ。

int sum( int*p ) {
   s = 0 ;
   for( __________ ; __________ ; __________ ) {
      ____________________ ;
   }
   return s ;
}
int array_a[ 4 ] = { 11 , 22 , 33 , 0 } ;
int array_b[ 5 ] = { 4 , 3 , 2 , 1 , 0 } ;
void main() {
   printf( "%d\n" , sum( array_a ) ) ; // 66 を表示
   printf( "%d\n" , sum( brray_b ) ) ; // 10 を表示
   printf( "%d\n" , sum( array_a + 1 ) ) ; // 何が表示される?
}

リスト構造

では、最後のシメということで、リスト構造でのポインタのイメージの確認。

// リストを次々たどる処理
struct List {
   int          data ;
   struct List* next ;
} ;
struct List* cons( int x , struct List* p ) {
   struct List* ans =
      (struct List*)malloc( sizeof( struct List ) ) ;
   if ( ans != NULL ) {
      ans->data = x ;
      ans->next = p ;
   }
   return ans ;
}
void main() {
   struct List* top =
      cons( 11 , cons( 22 , cons( 33 , NULL ) ) ) ;
   struct List* p ;
   for( p = top ; p != NULL ; p = p->next ) {
      printf( "%d¥n" , p->data ) ;
   }
}
// メモリのイメージで
typedef int pointer ;
int memory[ 1000 ] = {
   0  , 0 ,
   22 , 6 ,
   11 , 2 ,
   33 , 0 ,
   0  , 0 ,
} ;
#define OFFSET_DATA 0
#define OFFSET_NEXT 1
void main() {
   pointer p ;
   for( p = 4 ; p != 0 ; p = memory[ p + OFFSET_NEXT ] ) {
      printf( "%d¥n" , memory[ p + OFFSET_DATA ] ) ;
   }
}

授業アンケート(前期修了)

2018年度前期修了科目の授業アンケート。

オブジェクト指向プログラミング(専攻科)

専攻科オブジェクト指向は、80.5 で前年度ともあまり変わらないポイント。

板書については、Webに授業資料を公開しながらの授業であったため、評価が高かった。興味と関心についても評価が高い一方で、内容理解についてはポイントも低く、レポートなどを見ていると、プログラミングが苦手な人の参加も多かったように思う。もう少し理解に割く時間を増やしても良かったかもしれない。準備についての評価が低い。Web資料も準備しながらなので、準備はもう少し高いことを期待していた。

情報制御基礎(3年学際科目)


今年初めて実施の学際科目で、他学科の学生も受講する内容。このため、プログラミング経験の浅いM,C,Bの学生には、厳しい内容だった。しかし、情報制御という授業でプログラミング無しで、簡単なデータ処理を行うために2重forループも分からないのでは、授業で教える内容が無い。最初のガイダンスで、選択科目だしプログラミングが苦手なら受講を避けるようにすべきだったと思う。

学科サイトを安全に保護されたページに

最近のWebページでの SSL 接続必須の状況の中、メジャーなブラウザは https 接続が不完全だと、ページURL横の🔒マークが表示されなくなってきている。

その中で、学科のページも https の SSL 鍵なども登録していたけど、久々にページを確認したら🔒マークが消えている。原因は、サイドメニューにプロコン公式ページへのリンクのためのバナー画像を http で表示させていた。かといって、プロトコル欄を https に変更したら、プロコンのサイトが SSL 鍵が公式でなかった。

プロコンのページは電子情報では興味を持つ人も多いので、バナーアイコンをコピーしておくことにした。

IchigoJamでの公開講座

電子情報工学科のOBの jig.jp 福野氏に講師として協力してもらい、中学生向けの公開講座が行われました。

システム

最新の投稿(電子情報)

アーカイブ

カテゴリー