280 likes | 480 Views
pointer (ตัวชี้). เนื้อหาที่สอนในวันนี้. ขั้นตอนการประกาศตัวแปรในภาษาซี ตัวแปรชนิด pointer การกำหนดค่าให้กับตัวแปร pointer การใช้งานตัวแปร pointer pointer กับนิพจน์ทางคณิตศาสตร์ สิ่งที่ต้องระวังในการใช้งาน pointer pointer กับตัวแปร array. ขั้นตอนการประกาศตัวแปรในภาษาซี.
E N D
เนื้อหาที่สอนในวันนี้เนื้อหาที่สอนในวันนี้ • ขั้นตอนการประกาศตัวแปรในภาษาซี • ตัวแปรชนิด pointer • การกำหนดค่าให้กับตัวแปร pointer • การใช้งานตัวแปร pointer • pointer กับนิพจน์ทางคณิตศาสตร์ • สิ่งที่ต้องระวังในการใช้งาน pointer • pointer กับตัวแปร array #07 pointer
ขั้นตอนการประกาศตัวแปรในภาษาซีขั้นตอนการประกาศตัวแปรในภาษาซี • การประกาศตัวแปรในโปรแกรม -> การกำหนดพื้นที่ในหน่วยความจำเพื่อใช้ในการเก็บค่าของตัวแปรนั้นๆ • int x = 25; -> การกำหนดพื้นที่ในหน่วยความจำสำหรับตัวแปรชื่อ x ที่มีค่าข้อมูลชนิดจำนวนเต็ม โดยกำหนดค่าเริ่มต้นไว้ในพื้นที่หน่วยความจำ ณ ตำแหน่งดังกล่าวเป็น 25 • ดังนั้น ค่า 25 จะถูกจัดเก็บในหน่วยความจำ ณ ตำแหน่งหนึ่งในหน่วยความจำ โดยมีตัวแปร x เพื่อใช้ในการอ้างถึงตำแหน่งนั้น #07 pointer
0xFFF0 0xFFF0 int x x = 25 x 0xFFF2 0xFFF2 x 25 0xFFF4 0xFFF4 • สมมุติตำแหน่งในหน่วยความจำดังกล่าวคือ ตำแหน่ง FFF216 ( address ที่ FFF216 ) • เมื่อเราอ้างถึงตัวแปร xก็คือการอ้างถึงข้อมูลที่เก็บอยู่ในหน่วยความจำตำแหน่ง FFF216นั่งเอง เช่น x = x + 10; #07 pointer
0xFFF2 px 0xFFEE 0xFFF0 25 0xFFF2 x 0xFFF4 ตัวแปรชนิด pointer • นอกจากตัวแปรธรรมดา (int, long, float, double, short, char) แล้วภาษาซียังมีตัวแปรชนิดพิเศษซึ่งใช้เก็บตำแหน่ง (address) ในหน่วยความจำของตัวแปรชนิดอื่นๆ ได้ ซึ่งจะเรียกว่า ตัวแปรชนิด pointer (ตัวชี้) xเป็นตัวแปรชนิด int pxเป็นตัวแปรชนิด pointer ที่ชี้ไปยัง int #07 pointer
การประกาศตัวแปรชนิด Pointer Type * Variable_Name; • Type : ชนิดของตัวแปร • * : เป็นเครื่องหมายที่แสดงว่าตัวแปรที่ตามหลังเครื่องหมายนี้เป็นตัวแปรชนิด pointer • Variable_Name: เป็นชื่อตัวแปรที่ต้องการประกาศว่าเป็นตัวแปรชนิด pointer โดยมีกฎการตั้งชื่อเหมือนตัวแปรทั่วไป #07 pointer
ข้อควรจำ เมื่อเราต้องการประกาศตัวแปร pointer เพื่อชี้ (เก็บค่า address) ไปยังตัวแปรชนิดใด เราจำเป็นต้องประกาศตัวแปร pointer ให้มีชนิดข้อมูลเป็นชนิดเดียวกับตัวแปรนั้นด้วย • ตัวอย่าง int *pt_i ; หมายความว่า pt_i เป็นตัวแปร pointer ที่ชี้ ไปยังข้อมูลชนิด integer float *pt_f ; หมายความว่า pt_f เป็นตัวแปร pointer ที่ชี้ ไปยังข้อมูลชนิด float #07 pointer
การกำหนดค่าให้ตัวแปร pointer float a = 3.5; float *pa ; • จากตัวอย่างเป็นการกำหนดให้aเป็นตัวแปรชนิด float เก็บค่า 3.5 และpaเป็นตัวแปรpoiterที่จะชี้ไปยัง a • เมื่อกำหนดตัวแปรชนิด pointer แล้วในตอนต้นตัวแปร pointer ที่ได้จะเก็บค่า address ขยะ (เราไม่สามารถทราบได้ว่าเป็น address ตำแหน่งใด) • ดังนั้นเราต้องกำหนดให้ตัวแปร pointer เก็บค่า address ของตัวแปรที่เราต้องการ #07 pointer
การกำหนดให้ตัวแปร pointer เก็บค่า address ของตัวแปรอื่นกำหนดได้โดยอาศัยเครื่องหมาย& (address operator) pa = &a ; • หมายถึงให้นำค่า address ของตัวแปรaไปจัดเก็บไว้ในตัวแปร pointer pa ( หรืออาจกล่าวได้อีกอย่างว่าเป็นการกำหนดให้ pointer pa ชี้ไปยังตัวแปร a ) • เมื่อมีเครื่องหมาย & อยู่หน้าตัวแปรใดจะหมายถึง address ของตัวแปรนั้น (ยกเว้นตัวแปร pointer) #07 pointer
pa1 0xFFF6 0xFFEE 0xFFF6 pa2 0xFFF2 3.5 0xFFF6 a 0xFFFA • ตัวแปรชนิด pointer เป็นตัวแปรที่เก็บค่า address • สามารถมีตัวแปร pointer สองตัวที่ชี้ไปยังตัวแปรตัวเดียวกัน (เก็บค่า address ตำแหน่งเดียวกัน) float a = 3.5 , *pa1 , *pa2 ; pa1 = pa2 = &a ; #07 pointer
การใช้งานตัวแปร pointer • เราสามารถเข้าถึงค่าที่จัดเก็บอยู่ใน address ตำแหน่งที่ตัวแปร pointer ชี้อยู่ได้ โดยอาศัย * (star operator) เพื่อเข้าถึงค่านั้นๆ float a = 3.5 , b; float *pa ; pa = &a ; b = *pa ; • ตัวแปรbจะมีค่าเท่ากับ 3.5 เนื่องจากเป็นการนำค่าที่เก็บอยู่ใน address ที่ตัวแปร paเก็บไว้ไปใส่ (ตำแหน่งเดียวกับตัวแปรa ) #07 pointer
ถ้าเราต้องการอ้างถึง address ของตัวแปร pointer ใดๆอีกต่อหนึ่ง เราสามารถอ้างถึงโดยใช้ตัวแปรนั้นโดยตรง float a = 3.5 , b; float *pa , *ptr; pa = &a ; b = *pa ; ptr = pa ; pa 0xFFF4 0xFFF0 a 3.5 0xFFF4 ptr 0xFFF4 0xFFF8 b 3.5 0xFFFC #07 pointer
ตัวอย่าง int a = 1 , b = 3 , *p1 , *p2 ; p1 = &a ; p2 = &b ; b = *p1 ; 1 a = *p2 + 5 ; 2 *p1 = 5 ; 3 *p2 = *p1 ; 4 หลังจากผ่านคำสั่งหมายเลข 1, 2, 3, 4 ? 1 2 3 4 3 line b=*p1 a=*p2+5 *p1=5 *p2=*p1 a 0xFFF0 1 1 6 5 5 b 0xFFF2 3 1 1 1 5 p1 0xFFF4 0xFFF0 0xFFF0 0xFFF0 0xFFF0 0xFFF0 p2 0xFFF6 0xFFF2 0xFFF2 0xFFF2 0xFFF2 0xFFF2 #07 pointer
pointer กับนิพจน์คณิตศาสตร์ • เราสามารถใช้นิพจน์คณิตศาสตร์ร่วมกับตัวแปร pointer ได้เช่น int a = 1 , b = 3 , *p1 , *p2 ; p1 = &a ; p2 = &b ; a = *p2 + 1 ; • เป็นการนำค่าที่จัดเก็บอยู่ในตัวแปรที่ pointer p2ชี้อยู่ (ตัวแปรb) มาบวกกับตัวเลข 1 จากนั้นจึงจัดเก็บผลลัพธ์ไว้ในตัวแปรa #07 pointer
สิ่งที่ต้องระวังในการใช้งาน pointer • ตัวแปร pointer สามารถนำมาดำเนินการทางคณิตศาสตร์ได้ แต่ความหมายที่ได้อาจผิดพลาด เช่น a =* ( p1 + 1 ) ; • สามารถทำได้ แต่จะหมายถึงการเพิ่มค่า address ที่ตัวแปร pointer ชี้ไปอีก 1 ตำแหน่ง แล้วจึงหาค่าที่จัดเก็บอยู่ใน address ตำแหน่งนั้น (ซึ่งเราไม่ทราบว่าเป็นตำแหน่งอะไร) #07 pointer
สิ่งที่ต้องระวังในการใช้งาน pointer • ในทำนองเดียวกัน เมื่อเราทำงานกับตัวแปรปกติทั่วไป และมีการใช้ & operator เพื่อหาค่า address ของตัวแปรนั้น เช่นp1 = &a + 1 ; • สามารถทำได้ แต่จะหมายถึงการเพิ่มค่า address ของตัวแปร a อีก 1 ตำแหน่ง แล้วจัดเก็บ address นั้นไว้ในตัวแปร pointer p1 ซึ่งผิดความหมายไป #07 pointer
สิ่งที่ต้องระวังในการใช้งาน pointer • ในการทำงานกับตัวแปร pointer ต้องกำหนดค่าเริ่มต้นให้กับตัวแปร pointer ก่อนเสมอว่าต้องการให้ชี้ไปยัง address ของตัวแปรใด (ใช้สัญลักษณ์ & ในการกำหนด) จากนั้นจึงจะสามารถกระทำการใดๆกับค่าข้อมูลที่ pointer นั้นชี้อยู่ได้ (ใช้สัญลักษณ์ * ในการจัดการข้อมูล) int a = 2 , *p ; *p = 3 ; • ผิดเพราะเราไม่ทราบว่า pointer pจะชี้ไปที่ใด #07 pointer
pointer กับตัวแปร array • เราสามารถใช้ pointer ชี้ไปยังข้อมูลในแต่ละช่องของอาร์เรย์ได้ โดยอาศัยความจริงที่ว่า ถ้าทำการบวกตัวแปร pointer ตรงๆ จะหมายถึงการเพิ่มค่า address ที่ pointer นั้นชี้ไป (เลื่อนตำแหน่ง address ไปเป็นจำนวนช่องเท่ากับค่าที่นำมาบวก) • และโดยปกติแล้ว ในการจัดเก็บอาร์เรย์ลงในหน่วยความจำ จะจัดเก็บในลักษณะเป็นช่องเรียงต่อกันไปตามลำดับ #07 pointer
Memory address อาร์เรย์ pointer ข้อมูลที่เก็บ score[0] &FF00 78 s_ptr score[1] &FF02 56 s_ptr + 1 s_ptr + 2 score[2] &FF04 42 score[3] &FF06 83 s_ptr + 3 score[4] &FF08 25 s_ptr + 4 score[5] &FF0A 36 s_ptr + 5 s_ptr + 6 score[6] &FF0C 68 score[7] &FF0E 54 s_ptr + 7 #07 pointer
ตัวอย่าง #include <stdio.h> void main() { int sc[5] = {1,2,3,4,5} , *sc_ptr , a , b , c , d , e ; sc_ptr = &sc[0] ; a = *sc_ptr ; b = *(sc_ptr + 1) ; c = *(sc_ptr + 2) ; d = *(sc_ptr + 3) ; e = *(sc_ptr + 4) ; } a = 1 b = 2 c = 3 d = 4 e = 5 #07 pointer
ตัวอย่าง 1. #include<stdio.h> 2. void main() • { • int i; • float sum = 0.0 , data[5] , *f_ptr ; • f_ptr = data ;// f_ptr = &data[0]; • for( i = 0 ; i < 5 ; i++ )// read float data 5 times • { • printf( “ Give float data %d : " , i+1) ; • scanf( “ %f “ , (f_ptr+i) ) ; • } • do • { • sum += * ( f_ptr++ ) ;/* add them up */ • } while (f_ptr < &data[5] ) ; • printf( "Sum of all number is %f\n " , sum) ; • } #07 pointer
ข้อควรระวัง • ในการใช้ pointer ชี้ไปยังอาร์เรย์ สามารถทำได้ 2 วิธี คือ • sc_ptr = &sc[0] ;กำหนดให้ pointer เก็บค่า address ของอาร์เรย์ช่องแรก (ระบุ index = 0) • fptr = data ; กำหนดชื่อของอาร์เรย์ data ให้กับ pointer fptr โดยตรง (ไม่ต้องทำการระบุ index และไม่ต้องใส่เครื่องหมาย &) • ไม่สามารถใช้คำสั่ง sc_ptr = ≻ หรือ fptr = &data; ได้ • จริงๆ แล้วตัวแปรอาร์เรย์ก็เป็น pointer ชนิดหนึ่งนั่นเอง (pointer แบบคงที่, ไม่สามารถชี้ address อื่นได้) #07 pointer
ตัวอย่าง 1. #include<stdio.h> 2. void main() • { • int i; • float sum = 0.0 , data[5] ; • for( i = 0 ; i < 5 ; i++ )// read float data 5 times • { • printf( “ Give float data %d : " , i+1) ; • scanf( “ %f “ , &data[i] ) ; • } • i = 0 ; • do • { • sum += * ( data + i++ ) ;/* add them up */ • } while ( i <= 4 ) ; • printf( "Sum of all number is %f\n " , sum) ; • } #07 pointer
สรุปลักษณะการประกาศตัวแปรสรุปลักษณะการประกาศตัวแปร int a ; aคือตัวแปรที่ใช้เก็บข้อมูลชนิด int ธรรมดา int a[] = {1,2,3};หรือ int a[3] ; aคือตัวแปรชนิด pointer แบบคงที่ ที่เก็บ address ของอาร์เรย์ช่องแรก ( aเท่ากับ &a[0], *aเท่ากับ a[0] ) int *a ; aคือตัวแปรชนิด pointer ที่เก็บ address ของข้อมูลชนิด int (ชี้ไปยังข้อมูลชนิด int) #07 pointer
a[0] 1 0xFFEA a[1] 2 0xFFEC a[2] 3 0xFFEE 4 a[3] 0xFFF0 init 5 a[4] 0xFFF2 pa 0xFFF4 การบ้าน ถ้ากำหนดให้ส่วนของโปรแกรมใน main function เป็นดังนี้ init int a[5]={1,2,3,4,5} , *pa ; 1. pa = a; 2. pa = &a[1]; 3. pa++; 4. a[0] = *a+*pa; 5. *pa = *(a+3); 6. a[4] =*a+3; 7. *(pa-1) = 3x3; 8. a[1] =*(pa++); จงแสดงให้เห็นว่ามีการเปลี่ยนแปลงค่าในหน่วยความจำตำแหน่งต่างๆ อย่างไรบ้างหลังจากจบคำสั่งแต่ละคำสั่ง #07 pointer
a[0] 1 0xFFEA 2 a[1] 0xFFEC 3 a[2] 0xFFEE 4 a[3] 0xFFF0 init 5 a[4] 0xFFF2 0xFFF4 pa • init int a[5]={1,2,3,4,5} , *pa ; • 1. pa = a; • 2. pa = &a[1]; pa เก็บค่า add ของ a[1] • 3. pa++; เพิ่มค่าของ pa ไป 1 ตำแหน่ง • 4. a[0] = *a+*pa; a = ชี้อยู่ที่ a[0] บวก กับ ค่าที่ pa ชี้อยู่ • *pa = *(a+3); address ของ a เพิ่มขึ้น 3 จะไปชี้ที่ a[3] • ดังนั้น ตำแหน่งที่ pa ชี้อยู่จะเป็นค่า 4 1 1 1 4 4 2 2 2 4 2 1 2 3 4 5 3 3 3 4 3 4 4 4 4 4 5 5 5 5 5 0xFFEC 0xFFEE 0xFFEE 0xFFEE 0xFFEA a 0xFFE0
a[0] 1 0xFFEA 2 a[1] 0xFFEC 3 a[2] 0xFFEE 4 a[3] 0xFFF0 init 5 a[4] 0xFFF2 pa 0xFFF4 6. a[4] =*a+3; ค่าของ pointer a ซึ่งขณะนี้ ชี้ที่ a[3] ดังนั้น a[4] = 4+3 7. *(pa-1) = 3x3; pa -1 คือไปชี้ที่ a[2] 8. a[1] =*(pa++); ค่าของ a[1] จะมีค่าเท่ากับ address ของ pa เพิ่มขึ้น 1 ซึ่งก็คือ a[3] มีค่าเป็น 4 4 4 4 6 7 8 4 4 9 4 4 4 4 4 4 7 7 7 a 0xFFE0 0xFFEE 0xFFEC 0xFFEE
ส่ง Address รับด้วย Pointer รูปแบบ การส่งตัวแปรแบบอ้างอิงไปยังฟังก์ชัน หรือแบบ argument and pointer หรือแบบ pass byreference หรือ Call by Reference วิธีการส่งตัวแปรแบบอ้างอิงไปยังฟังก์ชัน หรือการเรียกใช้ฟังก์ชัน Call by Referenceใช้รูปแบบ ดังนี้ ชื่อฟังก์ชัน (&ตัวแปร) ; การเขียนส่วนหัวของตัวฟังก์ชัน ใช้รูปแบบ ดังนี้ ชนิดข้อมูล ชื่อฟังก์ชัน (ชนิดข้อมูล *ตัวแปรชนิดตัวชี้) ชนิดข้อมูลประกาศให้ตรงกันกับตัวแปรที่ส่งมา ***หลักการใช้งานฟังก์ชันแบบ by reference คือ ส่ง Address จะรับด้วย pointer