リストの考え方の導入
テストを明日からに控え、新しい所に入りたくはないけど、 配列の利点や欠点を理解するためにも、ランダムアクセスやシーケンシャルアクセスの 話を取り混ぜながら、導入説明を行う。
配列の添字でリスト
struct List { int data ; int next ; } ; int top = 2 ; struct List table[] = { { 56 , 1 } , // 0 { 78 , -1 } , // 1 { 12 , 3 } , // 2 { 34 , 0 } , // 3 } for( int p = top ; p >= 0 ; p = table[ p ].next ) { printf( "%d" , table[ p ].data ) ; }
次のアドレスでリスト
struct List { int data ; struct List* next ; } ; struct List* top ; top = (struct List*)malloc( sizeof( struct List ) ) ; top->data = 12 ; top->next = (struct List*)malloc( sizeof( struct List ) ) ; top->next->data = 34 ; top->next->next = (struct List*)malloc( sizeof( struct List ) ) ; top->next->next->data = 56 ; top->next->next->next = NULL ; struct List* p ; for( p = top ; p != NULL ; p = p->next ) printf( "%d" , p->data ) ;
ポインタで配列をスキャン&bit演算
例年のテスト問題の範囲を確認して、bit演算の話をしたけど、 先週の授業でのポインタのネタが不完全だったので、 その続きを後半で説明をした。
ポインタで配列をスキャン
ポインタの説明ということで、今週はアドレス渡しによるプログラムを説明。 分かりやすい例ということで、swap()を説明し、動作イメージを解説。
void swap( int* a , int* b ) { int temp = *a ; *a = *b ; *b = temp ; } void main() { int x = 11 , y = 22 , z = 33 ; swap( &x , &y ) ; swap( &y , &z ) ; }
次に、配列をポインタでスキャンするような処理で、 ポインタのインクリメントの説明。
分かりやすい事例として、配列末尾に終了目印(0)がついている内容の加算を考える。
int a[] = { 11 , 22 , 33 , 0 } ; int sum( int a[] ) { // 配列で書いてみる int s = 0 ; for( int i = 0 ; a[i] != 0 ; i++ ) s += a[i] ; return s ; } int sum( int* p ) { // ポインタで書いてみる int s = 0 ; for( ; *p != 0 ; p++ ) s += *p ; return s ; } int sum( int* p ) { // もっと短く int s = 0 ; while( *p != 0 ) s += *p++ ; return s ; }
ビット演算
2進数の理屈が分かっていれば、コンピュータ内部の電子回路的に行われている 掛算もプログラムで記述できる。この時、2進数の数値の処理ということで、 ビット演算が重要。
int mul( int x , int y ) { int s = 0 ; while( y != 0 ) { if ( y & 1 != 0 ) s += x ; x <<= 1 ; y >>= 1 ; } return s ; }