690 likes | 838 Views
Structure Programming การเขียนโปรแกรมแบบโครงสร้าง. สัปดาห์ที่ 11 ตัว แปรชี้ตำแหน่ง (Pointer). objectives. เพื่อให้นิสิตรู้จักและเข้าใจ ตัวแปรชี้ตำแหน่ง ในภาษาซี สามารถ เขียนโปรแกรมภาษาซี โดย ใช้ตัวแปรชี้ตำแหน่งได้
E N D
Structure Programmingการเขียนโปรแกรมแบบโครงสร้าง สัปดาห์ที่ 11 ตัวแปรชี้ตำแหน่ง(Pointer)
objectives • เพื่อให้นิสิตรู้จักและเข้าใจตัวแปรชี้ตำแหน่งในภาษาซี • สามารถเขียนโปรแกรมภาษาซีโดยใช้ตัวแปรชี้ตำแหน่งได้ • สามารถนำความรู้เรื่องตัวแปรชี้ตำแหน่งไปประยุกต์เพื่อแก้ไขโจทย์ปัญหาในชีวิตประจำวันได้ได้อย่างถูกต้องเหมาะสม
Outline 1 Pointer 2 Arithmetic & Pointer Operator p 3 Array of Pointer& Array-Pointer Relate Pointer to Pointer & Pointer to Structure 4 5 Assignment
ที่อยู่ 10000 10001 10002 10003 10004 10005 10006 10007 ข้อมูล Variable Declaration • เมื่อมีการประกาศตัวแปรใดๆ เช่น int number; char letter; คอมไพเลอร์จะทำการจองพื้นที่ในหน่วยความจำสำหรับเก็บค่าตัวแปร number และค่าตัวแปร letter สมมุติว่าเป็นตำแหน่งหน่วยความจำที่ 10000 และ 10002 เมื่อมีการกำหนดจะทำการจองหน่วยความจำดังนี้ number=5; letter=‘A’; 5 ‘A’ number letter
Variable Declaration(cont.) ที่อยู่ของข้อมูล (Address) ข้อมูล ประเภท ชื่อตัวแปร ขนาด 0000 15 count 2 bytes int 0001 0002 3.1415 0003 pi float 4 bytes 0004 0005 0006 'A' char ch 1 bytes … … XXXX … …
Type Bits Bytes int 16 2 unsigned int 16 2 long 32 4 unsigned long 32 4 char 8 1 unsigned char 8 1 float 32 4 double 64 8 long double 80 10 Size of Variable (cont.)
Basic Knowledge of Pointer • ภาษาซีมีตัวแปรที่มีส่วนทำให้โปรแกรมกระชับยิ่งขึ้นในการทำงาน ตัวแปรชนิดนี้เรียกว่า“ตัวแปรชี้ตำแหน่ง หรือ พอยน์เตอร์ (Pointer)” • พอยน์เตอร์ หมายถึง ตัวแปรใดๆ ที่ใช้เก็บค่าของตำแหน่งที่อยู่ (Address) ของตัวแปรหรือข้อมูล • เมื่อเข้าถึงที่อยู่โดยพอยน์เตอร์ได้ก็จะสามารถกระทำกับข้อมูลได้ไม่ว่าจะเป็นการนำออกมาแสดงผลหรือกระทำกับตัวแปรอื่นๆ • ตัวแปรชนิดพอยน์เตอร์มีความเร็วในการทำงานสูง • ตัวแปรชนิดพอยน์เตอร์จะเก็บค่าที่อยู่ของหน่วยความจำหลัก ซึ่งต่างกับตัวแปรปกติที่เก็บค่าที่แท้จริงของข้อมูล นั่นคือการใช้ตัวแปรชนิดพอยน์เตอร์จะเป็นการเข้าถึงข้อมูลหรือเป็นการอ้างถึงตำแหน่งที่เก็บข้อมูล
Pointer Declaration type*pointer_name typeคือ ชนิดของตัวแปรประเภทตัวชี้ (pointer) *คือ เครื่องหมายแสดงว่าเป็นตัวแปรประเภทตัวชี้ pointer_nameคือ ชื่อของตัวแปรประเภทตัวชี้ • ตัวอย่างการใช้ตัวชี้ int*ptr_int; /* pointer to integer */ float*ptr_float;// pointer to float char*ptr_char; /* pointer to char */
Pointer Declaration (cont.) • ตัวแปรพอยน์เตอร์ทำหน้าที่เก็บตำแหน่งที่อยู่ของตัวแปรที่ชี้ นั่นคือทำหน้าที่ชี้ไปยังตัวแปรตัวอื่น ดังนั้นการประกาศตัวแปรพอยน์เตอร์ ต้องสอดคล้องกับชนิดของตัวแปรตัวอื่น ที่ต้องการให้ตัวแปรพอยน์เตอร์นั้นจะชี้ไปเช่น • char*prt; • int*ip , *temp; • double*dp; ประกาศตัวแปร prtให้เป็นตัวแปรพอยน์เตอร์ที่ชี้ไปยัง ตัวแปรชนิด char ประกาศตัวแปร ipและ ตัวแปร temp เป็นตัวแปรพอยน์- เตอร์ที่ชี้ไปยังตัวแปรชนิด int ประกาศตัวแปร dp เป็นตัวแปรพอยน์เตอร์ที่ชี้ไป ยังตัวแปรชนิด double
Referencing Operator “&” ตัวดำเนินการ & (Referencing Operator) ตัวดำเนินการ & ส่งกลับเลขที่อยู่ (Address) ของวัตถุ XXXX int count; 15 int *ptr; XXXX ptr = &count; /* ptrมีค่าเป็น XXXX */
How the pointer work? • ตัวดำเนินการอ้างถึงที่อยู่ (Reference/Address operator) จะใช้เครื่องหมาย & นำหน้าตัวแปร ซึ่งหมายถึงตำแหน่งที่อยู่ของตัวแปรนั้นในหน่วยความจำ #include <stdio.h> void main(void){ int z = 10; int *ZPtr; ZPtr = &z;/*ตัวแปรชนิดตัวชี้เก็บเลขที่อยู่ของตัวแปร z*/ }
Referencing Operator “&” (cont.) ที่อยู่ของข้อมูล (Address) ข้อมูล ขนาด ประเภท ชื่อตัวแปร 0000 15 count 2 bytes int 0001 0002 3.1415 0003 pi float 4 bytes 0004 0005 0006 'A' char ch 1 bytes … ptr = &count ตัวชี้ ptr ชี้ไปที่อยู่ของ ตัวแปรชื่อ count XXXX 0000 …
Referencing Operator “&” (cont.) ที่อยู่ของข้อมูล (Address) ชื่อตัวแปร ขนาด ประเภท ข้อมูล count 2 bytes int 15 0000 pi float 4 bytes 3.1415 0002 'A' 0006 char ch 1 bytes 0006 char *ptr_char = &ch; 0002 float *ptr_float = π 0000 int *ptr_int = &count;
Dereference Operator “*” เป็นตัวดำเนินการเชิงอ้อม (Indirection) หรือกลับการอ้างอิง (Dereferencing) ตำแหน่งที่XXXX 15 int count; XXXX int * ptr; int count = 15, y, z[10]; int *ptr; /* ptr เป็นตัวชี้ int */ ptr= &count; /* ptr ชี้ไปที่ count */ y = *ptr; /* y มีค่า 15 */ *ptr = 0; /* count มีค่า 0 */ ptr = &z[0]; /* ptr ชี้ไปที่ z[0] */
Dereference Operator “*” (cont.) • ตัวดำเนินการอ้างถึง (Dereferencing operator) ใช้เครื่องหมาย * นำหน้าตัวแปรพอยน์เตอร์ จะเป็นการอ้างถึงค่าข้อมูลที่ตัวแปรพอยน์เตอร์นั้นชี้ไป ซึ่งค่าข้อมูลนี้สามารถเปลี่ยนแปลงค่าได้ #include <stdio.h> void main(void){ int x; int y = 20; int *z; z = &y; x = *z;/*เป็นการอ้างถึงค่าข้อมูลที่ตัวแปรชนิดตัวชี้*/ printf (“%d”, x)/*ได้ผลลัพธ์คือ 20*/ } • ให้ตัวแปรพอยน์เตอร์ z ชี้ไปยังแอดเดรสของตัวแปร y โดยการให้ z เก็บตำแหน่งแอดเดรสของ y นั้นเอง
How to show the pointer value? • ฟังก์ชัน printfสามารถแสดงตำแหน่งที่อยู่ (address) ได้โดยใช้ • เครื่องหมาย %p เพื่อแสดงตำแหน่งเป็นเลขฐานสิบหก • เครื่องหมาย %u เพื่อแสดงตำแหน่งเป็นเลขฐานสิบ • ผลลัพธ์ที่ได้จะอยู่ในรูปแบบ XXXX:YYYYหรือ XXXXขึ้นอยู่กับ Memory Model ที่ใช้
letter num point D 19 26.09 0000 0002 0004 pt_point pt_num pt_letter ???? ???? ???? Example 1 #include<stdio.h> #include<conio.h> int main() { char letter = 'D'; int num = 19; float point = 26.09; char *pt_letter; int*pt_num; float *pt_point; pt_letter= &letter; pt_num= # pt_point= &point; printf("Address of letter = %p \n",pt_letter); printf("Address of num = %p \n",pt_num); printf("Address of point = %p \n",pt_point); return 0; } 0002 0000 0004
letter num point D 19 26.09 0000 0002 0004 pt_letter pt_num pt_point 0000 0002 0004 ???? ???? ???? Example 1 (cont.) Address of letter = 0000 Address of num = 0002 Address of point = 0004
Example 2 int main() { int num1= 113,num2; float price1 = 4.85; char hint1= 'J',hint2; int*pt_num; float *pt_price; char *pt_hint; pt_num= &num1; pt_price= &price1; pt_hint= &hint1; num2= *pt_num; hint2= *pt_hint; printf("Variable num1= %d \n", num2); printf("Variable price1 = %f \n",*pt_price); printf("Variable hint2= %c \n", hint2); return 0; } num1 price1 hint1 113 4.85 J --x-- --y-- --z-- pt_num pt_price pt_hint --x-- --y-- --z-- num2 hint2 113 J
Example 2 (cont.) num1 price1 hint1 113 4.85 J Variable num1= 113 Variable price1 = 4.850000 Variable hint2= J --x-- --y-- --z-- pt_num pt_price pt_hint --x-- --y-- --z-- num2 hint2 113 J
printf ("The address of a is %p\n" "The value of aPtr is %p\n\n", &a, aPtr); printf ("The value of a is %d\n" "The value of *aPtr is %d\n\n", a, *aPtr); printf ("Proving that * and & are complements of " "each other.\n&*aPtr = %p\n*&aPtr = %p\n", &*aPtr, *&aPtr); The address of a is FFF4 The value of aPtr is FFF4 The value of a is 7 The value of *aPtr is 7 Proving that * and & are complements of each other. &*aPtr = FFF4 *&aPtr = FFF4 The Other Format of Reference and Dereference Operators FFF4 7 a ???? FFF4 aPtr int a; /* a is an integer */ int *aPtr; /* aPtr is a pointer to an integer */ a = 7; aPtr = &a; /* aPtr set to address of a */ The address of a is FFF4 The value of aPtr is FFF4 The value of a is 7 The value of *aPtr is 7 Proving that * and & are complements of each other. &*aPtr = FFF4 *&aPtr = FFF4
variable2 variable1 d ---- 1906 Summary of Pointer Process การประกาศตัวแปรพอยน์เตอร์ type *pt_name; pt_name แสดงตำแหน่งข้อมูลด้วย “&” 1906 ---- แสดงข้อมูลด้วย “*” d variable2 = *pt_name;
Outline 1 Pointer 2 Arithmetic & Pointer Operator p 3 Array of Pointer& Array-Pointer Relate Pointer to Pointer & Pointer to Structure 4 5 Assignment
Arithmetic & Pointer Operator • คณิตศาสตร์ของตัวแปรชี้ตำแหน่งสามารถทำได้เพียงการบวก การลบ การเพิ่มค่าและการลดค่าเท่านั้น ไม่สามารถกระทำการคูณ หาร หรือการเลื่อนบิทเครื่องหมายทางคณิตศาสตร์ของพอยน์เตอร์ได้แก่ • + หมายถึง การบวก • – หมายถึง การลบ • ++ หมายถึง การเพิ่มค่าครั้งละ 1 • –- หมายถึง การลดค่าครั้งละ 1
Arithmetic & Pointer Operator (cont.) • เครื่องหมาย “+” และ “–” ใช้ได้เฉพาะตัวแปรชี้ตำแหน่งชนิดเลขจำนวนเต็มเท่านั้น • การบวกและลบตัวแปรชี้ตำแหน่งคือ การเลื่อนไปชี้ในตำแหน่งที่อยู่ของตัวแปรตามที่กำหนด กรณีที่ตัวแปร ipชี้ที่ตำแหน่ง 1000 เมื่อทำคำสั่งต่อไปนี้ int *ip; ip = &x; ip=ip+9; ค่าตัวแปรพอยน์เตอร์ “ip” จะเลื่อนไปชี้ที่ตำแหน่ง “1018”
Arithmetic & Pointer Operator (cont.) • การเพิ่มค่าครั้งละ 1 ของตัวแปรตัวชี้จะเป็นการเลื่อนตัวชี้พอยน์เตอร์ตามชนิดของตัวแปรที่ทำการชี้ เช่น พอยน์เตอร์ “ip” ชี้ตัวแปรประเภทจำนวนเต็มที่ตำแหน่ง “1000” เมื่อกำหนด ip++; คอมไพเลอร์จะทำการเลื่อนตัวชี้ “ip” ไปยังตำแหน่ง “1002” เพราะจำนวนเต็มเก็บ 2 ไบท์ int *ip; char *cp; float *fp; fp fp+1 ip ip+1 ip+2 1000 1001 1002 1003 1004 1005 1006 1007 ตำแหน่งที่อยู่ cp+6 cp+7 cp cp+1 cp+2 cp+3 cp+4 cp+5
Arithmetic & Pointer Operator (cont.) • นอกจากการกระทำทางคณิตศาสตร์ ตัวชี้ยังมีความสามารถทางตรรกะ(เปรียบเทียบกันได้) เช่นเดียวกันกับตัวแปรปกติ 1. == หมายถึง ตำแหน่งเดียวกัน 2. != หมายถึง ต่างตำแหน่งกัน 3. > หมายถึง ตำแหน่งสูงกว่า 4. >= หมายถึง ตำแหน่งสูงกว่าหรือเท่ากัน 5. < หมายถึง ตำแหน่งต่ำกว่า 6. <= หมายถึง ตำแหน่งต่ำกว่าหรือเท่ากัน เช่น &x[3] จะน้อยกว่า &x[5] เป็นต้น
Outline 1 Pointer 2 Arithmetic & Pointer Operator p 3 Array of Pointer& Array-Pointer Relate Pointer to Pointer & Pointer to Structure 4 5 Assignment
Pointer & Array • ตัวชี้และอาร์เรย์มีความสัมพันธ์กันอย่างมาก บ่อยครั้งมีการจัดการกับสมาชิกของอะเรย์โดยใช้ตัวแปรพอยน์เตอร์ เช่น กำหนดให้ x[10] แล้วทำลำดับต่อไปนี้ ip = &x[0];// ip = x; y = *ip; // เป็นการนำค่าที่ x[0] ส่งให้ตัวแปร y ที่ตำแหน่งใดๆสามารถอ้างได้โดยใช้พอยน์เตอร์บวกตัวชี้ตำแหน่ง ++ip; // (++ip) y = *ip;// เป็นการนำค่าที่ x[1] ส่งให้ตัวแปร y
Array-Pointer Relate • การนำตัวชี้อ้าง ตำแหน่งอาเรย์ต่างๆ (Array Pointer) พอยน์เตอร์ ตำแหน่งอาเรย์ X[0] ip X[1] ip+1 X[]={1,2,3,4,5,6} *(ip+4)= ? X[2] ip+2 X[3] ip+3 X[4] ip+4 X[5] ip+5
3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] Array-Pointer Relate (cont.) ตัวชี้และแถวลำดับในภาษาซีนั้น มีความใกล้ชิดกันอย่างมาก การประกาศ float v[5] เป็นการกำหนดแถวลำดับ vขนาด5นั่นคือกลุ่มของวัตถุติดกัน 5ชิ้นมีชื่อว่า v[0], v[1], v[2], v[3], v[4]
3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr Array-Pointer Relate (cont.) การประกาศfloat *vPtrและกำหนดให้ vPtrชี้ไปยังตัวแปรแถวลำดับvสามารถทำได้สองวิธีคือ วิธีที่ 1 vPtr = v; วิธีที่ 2 vPtr = &v[0];
3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr Array-Pointer Relate (cont.) การกำหนดx = *vPtrคือการสำเนาค่าใน v[0] มายังx
3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr Moving Pointer Array with “+=“ and “-=“ • เมื่อบวกหรือลบจำนวนเต็มกับตัวชี้แล้ว • ค่าของตัวชี้มิได้เพิ่มหรือลดลงตามตัวเลขจำนวนนั้น • ค่าของตัวชี้เพิ่มหรือลดตามตัวเลขจำนวนนั้นคูณกับขนาดของวัตถุที่ตัวชี้นั้นชี้อยู่ • ขนาด (ไบท์) ขึ้นกับประเภทของข้อมูลที่ใช้ในวัตถุนั้น • ตัวอย่าง(กำหนดขนาดของวัตถุชนิด float คือ 4 ไบท์) • vPtr += 2; // vPtr = vPtr+(2*4)// or vPtr = 3000+(2*4)
3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr 3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr Moving Pointer Array with “+=“ and “-=“ (cont.) • vPtr += 2; // vPtr = vPtr+(2*4)// or vPtr = 3000+(2*4) • หลังจากคำสั่งข้างต้นแล้ว vPtrจะชี้ไปที่ v[2]
3000 3004 3008 3012 3016 v[0] v[1] v[2] v[3] v[4] vPtr 3000 3004 3008 3012 3016 v[0] v[1] v[2] v[3] v[4] vPtr Moving Pointer Array with “+=“ and “-=“ (cont.) • vPtr -= 2; // vPtr = vPtr-(2*4)// or vPtr = 3008-(2*4) • หลังจากคำสั่งข้างต้นแล้วvPtrจะชี้ไปที่ v[0]
Moving Pointer Array with “+“ and “-“ 3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr vPtr+2 vPtr+4 vPtr+1 vPtr+3
Calculation Element by Pointer 3000 3004 3008 300C 3010 v[0] v[1] v[2] v[3] v[4] vPtr v2Ptr • vPtr = &v[0]; // vPtr = 3000 • v2Ptr = &v[2]; // or v2Ptr = 3008 • x = v2Ptr – vPtr; // x = ? ค่าที่ xได้รับคือจำนวนหน่วย (Element) ของตัวแปรแถวลำดับนับจาก vPtrถึงvPtr2 ในกรณีนี้คือ 2
num[3] num[4] num[0] num[1] num[2] 12 34 907 112 45 0410 0414 0412 0418 0416 pt_num 0350 temp 050A Using Pointer with Array int num[5] = {12, 34, 112, 45, 907}; int *pt_num; pt_num = &num[1]; 0412 0418 pt_num = &num[4]; int temp; temp = *pt_num; 907
num[0] num[1] num[4] num[2] num[3] 26.09 -4.24 -4.23 19.01 -13.12 0310 0300 0304 0308 030C Using Pointer with Array (cont.) type name[10]; type *pt_name; pt_name = name; //pt_name = &name[0] float num[] = {19.01, 26.09, -4.23, -4.24, -13.12}
pt_num +3 090D +1 test1 test2 num[3] num[2] num[4] num[1] num[0] 26.09 -13.12 19.01 -4.23 -4.24 032A 322E 0308 0300 030C 0310 0304 The Other Using Pointer with Array float *pt_num; 0300 pt_num = num; float test1, test2; test1 = *(pt_num+3); -4.24 26.09 test2 = *(pt_num+1);
Array of Pointer Type*Pointer_Array_Name[index]; typeคือ ชนิดของตัวแปรประเภทตัวชี้ตามข้อกำหนดของ Array *คือ เครื่องหมายแสดงว่าเป็นตัวแปรประเภทตัวชี้ Pointer_Array_nameคือ ชื่อชุดของตัวแปรประเภทตัวชี้ index คือ ขนาดของอาเรย์ที่จองไว้สำหรับเก็บชุดของตัว แปรประเภทตัวชี้
Example 3 #include<stdio.h> void main(void) { int a, b, c, *pa[3]; a=5; b=10; c=15; pa[0]=&a; pa[1]=&b; pa[2]=&c; printf(“\n pa 1=%d, 2=%d, 3=%d”,*pa[0],*pa[1],*pa[2]); }
Array int main() { int i, offset, b[] = {10, 20, 30, 40}; int *bPtr = b; /* set bPtr to point to array b */ printf("Array b printed with:\n" "Array subscript notation\n"); for (i=0; i<=3; i++) printf("b[%d] = %d\n", i, b[i]); return 0; } Array b printed with: Array subscript notation b[0] = 10 b[1] = 20 b[2] = 30 b[3] = 40
Using Array in Pointer Format int main() { int i, offset, b[] = {10, 20, 30, 40}; int *bPtr = b; /* set bPtr to point to array b */ printf("Pointer/offset notation where\n" "the pointer is the array name\n"); for (offset = 0; offset<=3 ; offset++) printf("*(b + %d) = %d\n", offset, *(b + offset)); return 0; } Pointer/offset notation where The pointer is the array name *(b + 0) = 10 *(b + 1) = 20 *(b + 2) = 30 *(b + 3) = 40
Using Pointer in Array Format int main() { int i, offset, b[] = {10, 20, 30, 40}; int *bPtr = b; /* set bPtr to point to array b */ printf("Pointer subscript notation\n"); for (i=0 ; i<=3 ; i++) printf("bPtr[%d] = %d\n", i, bPtr[i]); return 0; } Pointer subscript notation bPtr[0] = 10 bPtr[1] = 20 bPtr[2] = 30 bPtr[3] = 40
Outline 1 Pointer 2 Arithmetic & Pointer Operator p 3 Array of Pointer& Array-Pointer Relate Pointer to Pointer & Pointer to Structure 4 5 Assignment
Pointer to Pointer type **ptt_name; typeคือ ชนิดของตัวแปรประเภทตัวชี้ * * คือ เครื่องหมายแสดงว่าเป็นตัวแปรประเภทตัวชี้ ซ้อนตัวชี้ ptt_nameคือ ชื่อตัวแปรประเภทตัวชี้ซ้อนตัวชี้
ptt_time pt_time temp2 temp1 time 9.28 05C0 03AA 0510 0100 0250 Pointer to Pointer (cont.) float time = 9.28; float *pt_time; 0100 0250 float **ptt_time; pt_time = &time; ptt_time = &pt_time; float temp1; temp1 = *pt_time; 9.28 float temp2; temp2 = **ptt_time; 9.28