Chapter 9 ตัวชี้ pointer
หน่วยความจำ ... ... 20 21 22 23 24 25 26 27 28 29 ที่อยู่ (address) 20 21 22 23 24 25 26 27 28 29 ที่อยู่ (address) 1 byte
ทีอยู่ของข้อมูลภายในหน่วยความจำ ตัวแปร Variable ทีอยู่ของข้อมูลภายในหน่วยความจำ การอ้างอิงแบบตรง direct reference ตัวแปรทั่วไป (ordinary variable) การอ้างอิงแบบอ้อม indirect reference ตัวแปรตัวชี้ (pointer variable)
การอ้างอิงแบบตรง Direct reference int main() {char c; int i; float f; ... ... 20 21 22 23 24 25 26 27 28 29 int main() {char c; int i; float f; ... } c address = 20 f address = 21 i address = 26
int k; int m; การอ้างอิงแบบตรง Direct reference k = m = 0; k m k m address int k; k 2540 int m; 1672 m k = m = 0; 2540 k m 1672 pointer
int k; int m; k = m = 0; k m k m absolute address symbolic address 2540 int m; 1672 m k = m = 0; 2540 k 1672 m
การอ้างอิงแบบอ้อม Indirect reference 50 56 54 ... ... 20 21 22 23 24 25 26 27 28 29 c address = 20 f address = 21 i address = 26 int main() {char *c; int *i; float *f; ... } 50 51 52 53 54 55 56 57 58 59
Pointer เป็น ประเภทข้อมูลพื้นฐาน (Basic data type) ค่าที่ pointer ชี้ไปอาจเป็นชนิด int, double, char เป็นต้น
การประกาศตัวแปรตัวชี้ data type *variable name; ต้องประกาศก่อนใช้งาน ในการประกาศ ต้องระบุว่า pointer ชี้ไปที่ตัวแปรหรือค่าประเภทใด * เป็น unary operator เรียกว่า เป็น indirect operator
Pointer variable declarations int *i; i ชี้ไปยังค่าประเภท int i float *f; f ชี้ไปยังค่าประเภท float f char *c; c ชี้ไปยังค่าประเภท char c double *d d ชี้ไปยังค่าประเภท double d i, f, c, d เป็นตัวแปรประเภท pointer char *c1, *c2; float *value, percent;
Pointer variable initialization 1. NULL 2. Zero 3. address
NULL Pointer Pointer ที่ไม่ได้ชี้ไปทีไหนเลย Pointer ที่ไม่ได้เก็บ address ใดๆ ไว้ NULL เป็นค่าคงที่ที่กำหนดไว้ใน <stdio.h> int *np; np = NULL; NULL np
Initializing pointer to 0 การกำหนดค่าเริ่มต้นของ pointer เป็น ศูนย์ มีความหมายเดียวกับ NULL มักใช้ในกรณีที่ต้องการเน้นว่า เป็นเหตุการณ์พิเศษ แต่ NULL เป็นที่นิยมกว่า int *np; np = 0; np
การกำหนดค่าเริ่มต้นให้ตัวชี้ int i i 2000 int *p p เก็บ ที่อยู่ ของค่าประเภท int p 3500 p = &i p เก็บ ที่อยู่ ของตัวแปร i p 2000 3500 scanf (“%d”,&i); i 30 2000 ป้อน 30 รับค่าจากแป้นพิมพ์ ตรวจสอบประเภทข้อมูลตามที่กำหนดไว้ นำค่านั้นไปเก็บใน address ที่กำหนด
Pointer variable initialization int i i 2000 int *p p 3500 p = NULL; p 3500 NULL p = &i p 2000 3500
2 1 3 4 int i, n; int *p; p = &i; n = *p; 5 i i 2000 2000 i = 5; n n 3000 int *p; 3000 p p 4000 4000 2 1 5 i 2000 5 i 2000 n p = &i; 3000 5 n n = *p; 3000 2000 p 4000 2000 p 4000 3 4
การเข้าถึงค่า โดยใช้ indirection operator * Dereferencing การเข้าถึงค่า โดยใช้ indirection operator * จะต้องเก็บ ที่อยู่ ไว้ในตัวแปร pointer (3) ก่อน จึงจะ dereference (4) ได้
int i, j, n; int *p; p = &i; n = *p; p i j n 20 40 60 100 i = 5; 20 40 *p = j 20 40 40 10 60 10 100 5 *p = *p + 2 20 40 40 12 60 10 100 5
printf (“i = %d\n”, i); i = 12 printf (“*p = %d\n”, *p); *p = 12 &i = 0040 printf (“&i = %d\n”,&i); &i = 0028 printf (“&i = %p\n”,&i);
call by value
Before main calls cube After cube receives the call int main () {int k = 5; k = cube (k); } int main () {int k = 5; k = cube (k); } k k 5 5 int cube (int n) {return n * n * n; } int cube (int n) {return n * n * n; } n 5 n is undefined
After cube returns to main After main complete the assignment to number k 125 int main () {int k = 5; k = cube (k); } int main () {int k = 5; k = cube (k); } k 5 125 int cube (int n) {return n * n * n; } int cube (int n) {return n * n * n; } n is undefined n is undefined
call by reference
Before the call by reference to cbref 4320 5 k n is undefined
After call by reference to cuberef and before *nptr is cubed call by reference void main() {int k = 5; cube (&k); } 4320 5 k 4320 4320 void cbref (int *nptr) {*nptr = *nptr * *nptr * *nptr; } nptr 4320 4320 5 k 5 5 5 4320 125 k
After *nptr is cubed call by reference void main() {int k = 5; cbref (&k); } 4320 k 125 void cbref (int *nptr) {*nptr = *nptr * *nptr * *nptr; } nptr 4320
Call by value
Call by reference t s s = 5 t = 10 s = 10 t = 5 xp 1000 yp 2000 temp 1000 5 2000 10 1000 10 s s = 5 t = 10 t 2000 5 s = 10 t = 5 xp 1000 yp 2000 1000, 2000 x = 5 y = 10 x = 10 y = 5 1000, 2000
xp yp 1000 2000 temp 1000 5 2000 10 temp = *xp; 1000 5 2000 10 5 *xp = *yp; 1000 10 2000 10 5 *yp = temp; 1000 10 2000 5 5
&k[0] &k[1] &k[2] &k[3] &k[4] &k[5] &k[6] k k+1 k+2 k+3 k+4 k+5 k+6 k เป็น pointer ที่ชี้ไปยัง k[0] k = &k[0] k เก็บ address ของ k[0] k+4 เป็น pointer ที่ชี้ไปยัง k[4] k+4 = &k[4] k+4 เก็บ address ของ k[4]
k + i = &k[i] *(k+i) = k[i] &k[0] &k[1] &k[2] &k[3] &k[4] &k[5] &k[6]
array subscript convert pointer dereference &k[0] &k[1] &k[2] &k[3] k[i] convert sizeof(int) pointer dereference *(k+i) k+ i x 2
&k[0] &k[1] &k[2] &k[3] &k[4] &k[5] &k[6] k k+1 k+2 k+3 k+4 k+5 k+6 *(k+i) ค่าที่ถูกชี้โดย k + i อยู่ที่ address k+ i x 2 *(k+5) ค่าที่ถูกชี้โดย k + 5 อยู่ที่ address k+ 5 x 2
#include <stdio.h> #define NUM 5 void main () {int i, grade[] = {90, 75, 56, 93, 68}; for (i = 0; i < NUM; i++) printf (“Element %d is %d\n”, i, *(grade + i)); } Element 0 is 90 Element 1 is 75 Element 2 is 56 Element 3 is 93 Element 4 is 68
k[0] k[1] k[2] k[3] k[4] k[5] k[6] k k+1 k+2 k+3 k+4 k+5 k+6 6000 6000 k = &k[0]; k
6000 k = &k[0]; k 5994 k -= 3; k 5996 k++; k 5998 ++k; k 5996 k--; k
Return largest and smallest array values through pointer parameters
Return largest and smallest array values through an array parameters
ค่าของ ptr อาจแก้ไขได้ แต่ค่าทีถูกชี้โดย ptr แก้ไขไม่ได้ Constants and Pointer ประกาศให้ ptr ชี้ไปยังค่าคงที่จำนวนเต็ม คำสั่งนี้ใช้ไม่ได้ ค่าของ ptr อาจแก้ไขได้ แต่ค่าทีถูกชี้โดย ptr แก้ไขไม่ได้
Arrays of Pointers color[0] color[1] color[2] color[3] ‘r’ ‘e’ ‘d’ ‘\0’ ‘w’ ‘h’ ‘i’ ‘t’ ‘e’ ‘\0’ ‘b’ ‘l’ ‘a’ ‘c’ ‘k’ ‘\0’ ‘b’ ‘l’ ‘u’ ‘e’ ‘e’ ‘\0’ ชี้ไปยัง address ของอักขระแรก
compute average of array double tableAverage (int a[], int n) {double sum = 0.0; int i; for (i = 0; i < n; i++) sum += a[i]; return (n != 0) ? sum / n : 0.0; } double tableAverage (int a[], int n) {double sum = 0.0; int i; int *ptr ptr = a; for (i = 0; i < n; i++) { sum += *ptr; ptr++;} return (n != 0) ? sum / n : 0.0; } array subscriping version pointer version
int n [2][3] = {{16, 18, 20},{ 25, 26, 27}}; สร้างสมาชิกของ array สร้าง set of pointer constant ชื่อ n n[0] n[1]
n n[0][1] n[0][2] n[0][0] n [0] 16 18 20 n [1] 25 26 27 n[1][2] Address of n[0,0] n n[0][1] n[0][2] n[0][0] n [0] Address of n [0][0] 16 18 20 n [1] Address of n [1][0] 25 26 27 n[1][2] n[1][0] n[1][1]
16 18 20 25 26 27 Pointer notation Suscript notation value *n[0] n[0,0] 16 *(n[0]+1) n[0,1] 18 *(n[0]+2) n[0,2] 20 *n[1] n[1,0] 25 *(n[1]+1) n[1,1] 26 *(n[1]+2) n[1,2] 27 *(n[i]+j) n[i,j]
Pointer notation Suscript notation *n[0] *(*n) n[0,0] *(n[0]+1) *(*n+1) n[0,1] *(n[0]+2) *(*n+2) n[0,2] *n[1] *(*(n+1)) n[1,0] *(n[1]+1) *(*(n+1)+1) n[1,1] *(n[1]+2) *(*(n+1)+2) n[1,2]
กำหนด address เริ่มต้นของ array ไว้ใน pointer พิมพ์สมาชิกของ array โดยใช้ pointer/offset
กำหนด address เริ่มต้นของ array ไว้ใน pointer พิมพ์สมาชิกของ array โดยใช้ pointer/offset
พิมพ์สมาชิกของ array โดยใช้ ชื่อ array เป็น pointer
k[i][j] = *(k[i] + j) = *(*k+i) + j)
Dynamic memory allocation เป็นการใช้ ตัวแปร pointer ชี้ไปยังจุดเริ่มต้นของความจำ ที่ใช้จัดเก็บ แถวลำดับ ใช้ ฟังก์ชัน malloc เพื่อจองเนื้อที่ความจำ
malloc function memory allocation function
จัดสรรความจำ 1 ไบต์ แล้วนำ ที่อยู่ของความจำนี้ ไปเก็บไว้ใน point point = malloc(1); จัดสรรความจำ 1 ไบต์ แล้วนำ ที่อยู่ของความจำนี้ ไปเก็บไว้ใน point สำหรับตัวแปรที่ประกาศในโปรแกรม ความจำ 1 ไบต์นี้ ไม่มีชื่อ *point = ‘x’; (ค่าที่ถูก point ชี้ มีค่าเท่ากับ x) char *point; point = malloc(100); point ชี้ไปยัง ความจำขนาด 100 byte สำหรับสายอักขระ 99 ตัว (รวม null) มีการทำงานเช่นเดียวกับ char point[100]
char *string string = (char *) malloc(100) จัดสรรความจำสำหรับ 100 อักขระ int *x; x = (int *) malloc(10 * sizeof(int)) จัดสรรความจำสำหรับ แถวลำดับของจำนวนเต็มขนาด 10 จำนวน double *x; x = (double *) malloc(10 * sizeof(double)) จัดสรรความจำสำหรับ แถวลำดับของจำนวน double ขนาด 10 จำนวน
ใช้ตัวแปร pointer แทน array #define SIZE 10 int x[SIZE] int x[10]; int *x; x = (int *) malloc(10 * sizeof(int))
กรณีที่ มีการกำหนดค่าเริ่มต้น ไม่สามารถใช้ตัวแปรตัวชี้ได้ ต้องใช้ตัวแปรแถวลำดับเท่านั้น int x[10] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} int x[ ] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
Integer array defined as a pointer to an integer ใช้ scanf (“%d”, x + i) แทน scanf (“%d”, &x[i]) ใช้ printf (“%d”, *(x+i)) แทน printf (“%d”, x[i]) ใช้ *(x+i) แทน x[i] *(x+item) แทน x[item]
Advantage of dynamic memory allocation จองความจำเท่าที่ต้องการใช้ในระหว่างกระทำการ (malloc) คืนความจำเมื่อไม่ต้องการใช้งาน (free) สามารถจองและคืนความจำได้หลายครั้งในระหว่างกระทำการโปรแกรม
void (*foo)(int); foo เป็น pointer ชี้ไปยังฟังก์ชันที่มี 1พารามิเตอร์ชนิด int และไม่มีการคืนค่า คล้ายกับว่าจะประกาศฟังก์ชันชื่อ *foo ที่มี 1พารามิเตอร์ชนิด int และไม่มีการคืนค่า ถ้า *foo เป็นฟังก์ชัน หมายความว่า foo ต้องเป็น pointer ชี้ไปยัง ฟังก์ชัน (int *x หมายความว่า *x เป็น int ดังนั้น x เป็น pointer ไป int)