23.พอยน์เตอร์ Pointer

พอยน์เตอร์ 

Pointer 

ลอกมาจากhttp://marcuscode.com/lang/cpp/pointers

พอยน์เตอร์ เป็นตัวแปรที่ใช้เก็บตำแหน่งที่อยู่ของตัวแปร การใช้พอยน์เตอร์ เราสามารถเข้าถึงข้อมูลที่เราต้องการได้โดยตรงโดยการใช้ชื่อของตัวแปร และมันมีประโยชน์มากในการเขียนโปรแกรมด้วยภาษาที่สามารถจัดการหน่วยความจำได้ง่าย เช่น ภาษา C และภาษา C++

Address-of operator (&)

การใช้เครื่องหมาย ampersand (&) นำหน้าชื่อของตัวแปรจะส่งค่าที่อยู่ของหน่วยความจำกลับมา ที่อยู่ของหน่วยความจำนั้นสามารถได้มาในตอนที่โปรแกรมรันเท่านั้น มันบอกได้ว่าตัวแปรนั้นอยู่ที่ไหนในหน่วยความจำ สำหรับตัวอย่าง:
&myNumber;
คำสั่งนี้จะส่งค่าที่อยู่ของหน่วยความจำกลับมาที่จะแสดงในเลขฐาน 16 แต่ในบทเรียนนี้ ตัวอย่างของเราจะใช้เลขฐาน 10 เพื่อให้ง่ายต่อความเข้าใจของคุณ
int myNumber = 10;
cout << &myNumber;   // assume to be 1477
สมมติคำสั่งด้านบนจะแสดง 1477 ออกทางหน้าจอ นั่นหมายถึงตัวแปร myNumber มีตำแหน่งในหน่วยความจำคือ 1477 (physical address) ดังนั้น เราสามารถเข้าถึงข้อมูลของ myNumber ได้โดยตรงโดยการใช้หลายเลขที่อยู่ 1477

Dereference operator (*)

ในตัวอย่างก่อนหน้า ที่อยู่ของตัวแปรสามารถได้มาจากเครื่องหมาย ampersand ก่อนชื่อตัวแปร ในการที่จะเข้าถึงข้อมูลโดยการใช้ที่อยู่เหล่านี้ เราใช้ *myNumber เพื่อที่จะรับค่า
int myNumber = 10;
foo1 = &myNumber;   // 1477
foo2 = *foo1 ;
ในตัวอย่างนี้ แสดงให้คุณเห็นถึงวิธีการเข้าถึงข้อมูลเมื่อเรารู้ที่อยู่ของมัน เราสมมติ 1477 เป็นที่อยู่ myNumber เพราะว่าในความเป็นจริง เราไม่มีทางรู้ที่อยู่จริงๆ จนกว่าโปรแกรมจะรัน foo1 เก็บที่อยูของตัวแปร myNumber (1477) ได้รับค่าที่ตัวแปร foo1 ชี้ไปโดยการใช้ *foo1 และมันจะส่งค่า 10 กลับมายังตัวแปร foo2

Declaring pointers

อย่างสองตัวอย่างที่ผ่านมา เราได้แนะนำเกี่ยวกับการรับที่อยู่ของตัวแปรและการเข้าถึงข้อมูลของมัน แต่ก่อนที่เราจะใช้พอยน์เตอร์เราต้องประกาศมันขึ้นมาก่อนเหมือนตัวแปร เพราะว่าพอยน์เตอร์เป็นประเภทตัวแปรของมันเอง เหมือนกับชื่อของมัน "พอยน์เตอร์" เป้าหมายของมันเพื่อชี้ไปยังที่อยู่ในหน่วยความจำ มาดูตัวอย่างการประกาศพอยน์เตอร์
int *pointer;
float *p1;
double *p2;
ในตัวอย่าง เราได้สร้างตัวแปรพอยน์เตอร์ 3 ตัว การสร้างพอยน์เตอร์จะต้องเริ่มด้วยการประกาศประเภทของมัน เช่น (int, float, double) ประเภทที่ว่านี้ไม่ได้หมายถึงประเภทของพอยน์เตอร์ แต่มันหมายถึงประเภทของตัวแปรที่พอยน์เตอร์จะชี้ไป และตามด้วยชื่อของพอยน์เตอร์ และคุณจะเห็นว่าเราได้ใส่เครื่องหมาย star (*) นำหน้าก่อนชื่อของมัน คุณอย่าสับสนในเครื่องหมาย deference operator (*) ที่มันใช้ในการเข้าถึงข้อมูลที่พอยน์เตอร์ได้ชี้ไป ซึ่งมันมีความหมายที่แตกต่างกันอย่างที่ได้กล่าวไป
#include <iostream>
using namespace std;

int main()
{
    int myvar = 10;
    int *mypointer;
    mypointer = &myvar;
    *mypointer = 20;
    cout << myvar;
    return 0;
}
เมื่อเรารันโปรแกรมนี้ มันจะได้ผลลัพธ์ดังนี้
20
ในตัวอย่างนี้ เราได้สร้างพอยน์เตอร์ที่ชื่อว่า mypointer และประเภทของมันคือ int เพราะว่าเราต้องการที่จะใช้ตัวแปรพอยน์เตอร์นี้ไปยังตัวแปร myvay ซึ่งเป็นตัวแปรประเภทแบบ integer และคำสั่ง mypointer = &myvar เราให้พอยน์เตอร์ของเราชี้ไปที่ตำแหน่งที่อยู่ของ myvar ตอนนี้ เราสามารถทำทุกอย่างเกี่ยวกับที่อยู่ของตัวแปรพอยน์เตอร์ mypointer ดังนั้นเราได้กำหนดค่า 20 ไปยังตำแหน่งนั้น และสุดท้าย เราแสดงผล myvar เพื่อดูผลลัพธ์ของมัน

Pointers และ arrays

การใช้พอยน์เตอร์กับอาเรย์นั้นเป็นสิ่งที่มีประโยชน์มาก เพราะว่าเรารู้ว่าตำแหน่งของข้อมูลในอาเรย์นั้นอ้างอิงกับตำแหน่งแรกของอาเรย์
#include <iostream>
using namespace std;

int main()
{
    int mynum[5] = {10, 20, 30, 40, 50};
    int *mypoint;
    mypoint = mynum;
    *mypoint = 20;
    mypoint++;
    *mypoint = 80;
    mypoint = mynum;
    mypoint += 4;
    *mypoint = 100;

    for (int i = 0; i < 5; i++)
    {
        cout << mynum[i] << ", ";
    }
    return 0;
}
20, 80, 30, 40, 100,
ในตัวอย่างนี้ เราใช้พอยน์เตอร์ชี้ไปที่ mynum และพอยน์เตอร์จะชี้ไปที่หัวหรือข้อมูลอันแรกของอาเรย์ ถ้าเราไม่รู้ตำแหน่งของอาเรย์ที่แน่นอน การเพิ่มค่าของพอยน์เตอร์โดยการใช้ ++ นั่นหมายความว่าเป็นการชี้ไปตำแหน่งถัดไปของข้อมูลในอาเรย์ เมื่อเราทราบว่าข้อมูลในอาเรย์ทุกตัวมีขนาดที่เท่ากัน เราสามารถไปที่ตำแหน่งใดๆ ของอาเรย์ได้โดยการใช้ mypoint += x โดย x เป็นจำแหน่งที่เราต้องการไปนับจากตำแหน่งแรกของอาเรย์หรือตำแหน่งปัจจุบันที่พอยน์เตอร์ชี้อยู่

Pointers addresses

พอนย์เตอร์นั้นเก็บค่าที่อยู่ของ Memory ที่ข้อมูลนั้นถูกเก็บอยู่ ในการที่จะดูตำแหน่งที่ข้อมูลถูกเก็บอยู่ สามารถดูได้สองวิธี คือผ่านตัวแปรพอยน์เตอร์ หรือผ่านสัญลักษณ์ของ Memory address (&) มาดูตัวอย่าง
#include <iostream>
using namespace std;

int main()
{
    int mynum[5] = {10, 20, 30, 40, 50};
    int *mypoint = mynum;

    // via point
    for (int i = 0; i < 5; i++)
    {
        cout <<  "Address at " << i << " = " << mypoint << endl;
        mypoint++;
    }
    cout << endl;

    // via addressing symbol
    for (int i = 0; i < 5; i++)
    {
        cout <<  "Address at " << i << " = " << &mynum[i] << endl;
    }

    return 0;
}
และนี่เป็นผลลัพธ์เมื่อรันโปรแกรม โดยทั้งสองจะได้ผลลัพธ์เหมือนกัน
Address at 0 = 0x28fed0
Address at 1 = 0x28fed4
Address at 2 = 0x28fed8
Address at 3 = 0x28fedc
Address at 4 = 0x28fee0

Address at 0 = 0x28fed0
Address at 1 = 0x28fed4
Address at 2 = 0x28fed8
Address at 3 = 0x28fedc
Address at 4 = 0x28fee0

Pointer arithmetics

ในพอยน์เตอร์ ภาษา C++ ให้เราสามารถกระทำการทางคณิตศาสตร์กับตัวแปรพอยน์เตอร์ได้ ที่เราเพิ่งจะทำกันคือการทำให้พอยน์เตอร์ชี้ไปที่ที่อยู่ของตัวแปร มาดูตัวอย่างของพอยน์เตอร์กับการดำเนินการทางคณิตศาสตร์
int number = 8; // address 1277
int *p;
p = &number;
p++; // 1278
p--; // 1277
p+=1000; // 2277

int *p2;
p2 = &number;
*p2++;   // number = 9
มาสมมติว่าเรามีตัวแปร number ซึ่งที่ตำแหน่งที่อยู่ที่ 1277 และเราใช้พอยน์เตอร์ p ชี้ไปที่ 1277 (Number's address) หลังจากนั้นเราสามารถย้ายพอยน์เตอร์ไปยังที่ไหนก็ตามที่เราต้องการ โดยอ้างอิงตำแหน่งจาก 1277 และเราใช้ p2 เพื่อเปลี่ยนค่าของ number
ในบทนี้ เราได้ครอบคลุมพื้นฐานในเรื่องพอยน์เตอร์ ซึ่งมันมีประโยชน์ในการจัดการหน่วยความจำแบบไดนามิกส์ ที่เราจะเรียนในบทถัดไป
*************************************************************************************************
https://beginnersbook.com/2017/08/cpp-pointers/

********************************************************************************



Introduction to Pointers in C++, Tutorial on Pointers, C++ Pointers


https://www.youtube.com/watch?time_continue=6&v=W0aE-w61Cb8&feature=emb_logo
********************************************************************************


อีกหนึ่งบทความ...ลอกมาจากhttps://www.devxco.com/articles/readarticle.php?id=A00000000000002#page1
ตัวชี้หรือ pointer จะถูกเก็บไว้ในสแตกซึ่งใช้ในการเก็บตำแหน่งหน่วยความจำของ ตัวแปร อาร์เรย์ และสิ่งต่าง ๆ ภายในโปรแกรม อาจกล่าวได้ว่าตัวชี้เป็นการสร้างชนิดข้อมูลที่สามารถชี้ไปยังตำแหน่งหน่วยความจำที่ต้องการได้ซึ่งมีประโยชน์เมื่อไม่ทราบว่าจะต้องจองหน่วยความจำเป็นจำนวนเท่าใดแต่สิ่งหนึ่งที่ต้องจำไว้คือการใช้หน่วยความจำจะถูกควบคุมโดยระบบปฏิบัติการดังนั้นหากมีการใช้งานที่ผิดพลาดจะเกิดการแจ้งเตือนจากระบบปฏิบัติการเสมอ

ก่อนที่จะทำความเข้าใจเรื่องตัวชี้ต้องแยกความแตกต่างระหว่างตัวชี้กับตัวแปรทั่วไปเสียก่อน เพื่อให้ง่ายในการทำความเข้าใจจึงขอยกตัวอย่างโค้ดและภาพด้านล่างดังต่อไปนี้
1
2
int a=5;
char c=‘Z’;

เมื่อพิจารณาถึงข้อมูลที่อยู่ในหน่วยความจำจะมีลักษณะเป็นดังรูปด้านซ้ายมือจะเห็นว่าค่าของตัวแปร a มีค่าเป็น 5 ถูกเก็บไว้ที่ตำแหน่งหน่วยความจำ 0xbffd8b30 มีขนาด 4 ไบต์ขณะเดียวกันตัวแปร c จะถูกเก็บถัดจากตำแหน่งเดิมไปอีก 4 ไบต์ได้แก่ตำแหน่งที่ 0xbffd8b34 และมีค่าเป็น 'Z' มีขนาดเป็น 1 ไบต์
จะเห็นว่าตัวแปรทั่วๆไปเหล่านี้จะมีองค์ประกอบที่สำคัญอยู่สามประการ คือ
  1. ตำแหน่งหน่วยความจำของตัวแปร
  2. ค่าที่ตัวแปรเหล่านั้นเก็บไว้
  3. ขนาดหน่วยความจำที่ใช้ซึ่งดูได้จากประเภทของตัวแปร
ตามมาตรฐานของ C++ แล้วไม่ได้กำหนดขนาดของประเภทข้อมูลไว้ในลักษณะของจำนวนไบต์ แต่จะกำหนดไว้เป็นช่วงกว้างของข้อมูลที่เป็นไปได้ เช่นข้อมูลประเภท char จะมีค่าอยู่ในช่วง -127 ถึง 127 (ไม่ใช่ -128 ถึง 127 เนื่องจากต้องใช้หนึ่งบิตเพื่อรองรับการทำ 1's-complement เพื่อใช้วิเคราะห์เครื่องหมายนั่นเอง) ดังนั้นจำนวนไบต์ที่อ้างถึงในตัวอย่างนี้จะมีขนาดไม่แน่นอนขึ้นอยู่กับคอมไพล์เลอร์และระบบปฏิบัติการที่ใช้
หากมีการเพิ่มตัวชี้เข้ามาในโค้ดตัวอย่างดังนี้
1
2
3
int a=5;
char c=‘Z’;
int *ptr=&a;
จากโค้ดด้านบนได้ทำการเพิ่มตัวชี้ ptr สำหรับชี้ข้อมูลประเภท int และทำการชี้ไปยังตำแหน่งหน่วยความจำของตัวแปร a ซึ่งจะได้ลักษณะของข้อมูลที่อยู่ในหน่วยความจำดังรูปด้านล่าง

ตำแหน่งข้อมูลของตัวแปรในหน่วยความจำ

ตำแหน่งของตัวชี้ ptr ที่อยู่ในหน่วยความจำจะอยู่ถัดจากตำแหน่งของตัวแปร c ไปอีก 1 ไบต์ (อ้างตามขนาดความกว้างของข้อมูลที่ตัวแปร c ใช้) ดังนั้นตำแหน่งของตัวชี้ ptr จะอยู่ในตำแหน่ง 0xbffd8b35 และทำการเก็บค่าเป็นตำแหน่งของหน่วยความจำตัวแปร a คือ 0xbffd8b30
 จากโค้ดและภาพด้านบนจะเห็นว่าตัวชี้จะมีการเก็บข้อมูลเป็นตำแหน่งหน่วยความจำของตัวแปรอื่นๆ ซึ่งต่างจากตัวแปรทั่วๆไปที่เก็บค่าเอาไว้

ตัวชี้ สามารถชี้ไปยังสิ่งใดได้บ้าง

ในทางปฎิบัติแล้วตัวชี้สามารถชี้ได้ทุกอย่างตัวอย่างเช่น
  • ตัวแปร (Variables)
  • ชนิดข้อมูลที่สร้างขึ้นมาเอง
  • อะเรย์
  • โครงสร้างข้อมูล
  • วัตถุของคลาส
  • ฟังก์ชัน
 ความสามารถในการเข้าถึงข้อมูลโดยผ่านตัวชี้ เป็นความสามารถที่สำคัญที่มีในภาษา C และ C++ แต่ด้วยความอิสระในการเข้าถึงข้อมูลผ่านตัวชี้ทำให้โปรแกรมเมอร์ต้องใช้งานอย่างระมัดระวัง มิฉะนั้นโปรแกรมจะเกิดข้อผิดพลาดได้โดยง่ายซึ่งความผิดพลาดจากการใช้งานตัวชี้ ตรวจสอบได้ยากเนื่องจากความผิดพลาดที่เกิดขึ้นส่วนใหญ่จะมีลักษณะเป็น Runtime error (ข้อผิดพลาดของโปรแกรมที่เกิดขึ้นเมื่อโปรแกรมกำลังทำงานอยู่) และข้อผิดพลาดเหล่านี้ถือว่าเป็น Bug หลักๆ ของโปรแกรมที่เขียนด้วย C/C++

สัญลักษณ์ที่เกี่ยวข้องกับตัวชี้

ใน C และ C++ ได้จัดเตรียมสัญลักษณ์ที่เกี่ยวข้องกับตัวชี้ไว้สองตัวได้แก่ "&" เรียกว่า address operator และ "*" เรียกว่า the dereferencing หรือ pointer operator ซึ่งมีรายละเอียดดังต่อไปนี้

The Address Operator (&)

สัญลักษณ์นี้เมื่อวางไว้หน้าตัวแปรใดๆจะหมายถึงการส่งค่ากลับเป็นตำแหน่งหน่วยความจำของตัวแปร เช่นเมื่อทำการเขียนโค้ดเป็น
1
&a
จะหมายถึงการอ้างถึงตำแหน่งหน่วยความจำของตัวแปรออกมาซึ่งในที่นี้จะได้ค่าเป็น 0xbffd8b30 นั่นเอง

Dereferencing (*)

ค่าในตัวแปรปรกติทั่วๆไปจะเป็นการเข้าถึงโดยตรง แต่สำหรับตัวชี้จะมีลักษณะการเข้าถึงค่าในตัวแปรโดยอ้อมโดยใช้ตัวดำเนินการ Dereferencing (*) สาเหตุที่เรียกว่าเป็นการเข้าถึงโดยอ้อมเนื่องจากตัวชี้ไม่ได้เก็บค่าของตัวแปรที่ตัวเองชี้อยู่แต่เก็บค่าของตำแหน่งของตัวแปรที่อยู่บนหน่วยความจำดังนั้นเมื่อต้องการเข้าถึงข้อมูลของตัวแปรที่ตัวชี้ชี้อยู่คอมไพล์เลอร์จะต้องมีการทำงานเป็นสองขั้นตอนดังต่อไปนี้

การเข้าถึงโดยอ้อม

  1. ​ตรวจสอบว่าตัวชี้เก็บตำแหน่งหน่วยความจำใดอยู่
  2. กระโดดไปยังตำแหน่งหน่วยความจำนั้นเพื่อเข้าถึงค่าของตัวแปรที่ชี้อยู่

การกำหนดค่าเริ่มต้นให้กับตัวชี้

เมื่อมีการสร้างตัวชี้ควรจำไว้ว่า ต้องทำการกำหนดให้ค่าเริ่มต้นมีค่าเป็น NULL เสมอ มิเช่นนั้นอาจเกิดข้อผิดพลาดในการใช้งานได้ อย่างไรก็ตามเราสามารถกำหนดค่าเริ่มต้นได้หลายแบบดังนี้
1
2
3
4
5
int a=3;
int b=7;
int *ptr1 = &b;
int *ptr2 = ptr1;
int *ptr3 = &a;
โดยปรกติแล้วเมื่อทำการประกาศตัวชี้โดยไม่กำหนดค่าเริ่มต้น ข้อมูลที่มีอยู่ในตัวชี้จะขึ้นอยู่กับตำแหน่งหน่วยความจำที่ตัวชี้นั้นถูกเก็บไว้ซึ่งขึ้นอยู่กับว่าที่ตำแหน่งหน่วยความจำนั้นมีค่าเก่าเป็นค่าอะไร ซึ่งแน่นอนว่าไม่ใช่ค่าที่โปรแกรมต้องการใช้งานเราจะเรียกค่าเหล่านี้ว่าค่าขยะ ดังนั้นเพื่อไม่ต้องการให้เกิดข้อผิดพลาดระหว่างเรียกใช้งาน ให้กำหนดค่า NULL หรือ 0 ให้กับตัวชี้ที่ประกาศขึ้น ซึ่งหมายถึงยังไม่มีการจองหน่วยความจำดังนี้
1
2
3
int *iptr = NULL;
char *cptr = 0;
float *fptr = 0;

การจองและคืนหน่วยความจำของตัวชี้

ใน C++ จะใช้คำสั่ง new และ delete เพื่อจองและคืนหน่วยความจำของตัวชี้ตามลำดับ 

การใช้งาน new

ตัวดำเนินการ new ใช้ในการสร้างวัตถุหากจองหน่วยความจำได้ ค่าตำแหน่งหน่วยความจำเริ่มต้นจะถูกส่งกลับ หากจองไม่ได้จะส่ง bad_alloc exception กลับ หรือ NULL Pointer นอกจากนั้นยังสามารถกำหนดค่าเริ่มต้นได้อีกด้วยทั้งนี้การกำหนดค่าเริ่มต้นให้กำหนดในเครื่องหมาย ( ) ซึ่งมีลักษณะการใช้งานดังนี้
pointer = new type(initialisers);
ตัวอย่างเช่น
1
2
3
4
char* mike;
int* nilgun;
mike = new char('A');
nilgun = new int(1);
การใช้ new สามารถใช้ในการสร้างวัตถุได้ทีละหลายๆ ตัวพร้อมกันในรูปแบบเดียวกับอะเรย์ ทำให้การสร้างมีลักษณะเช่นเดียวกับอะเรย์ของวัตถุในหน่วยความจำแบบพลวัติ (dynamic memory) การสร้างจะใช้เครื่องหมาย [ ] ล้อมรอบจำนวนของวัตถุที่ต้องการสร้างดังตัวอย่างต่อไปนี้
1
2
float* numbers;
numbers = new float[4];

การใช้งาน delete

ทุกสิ่งทุกอย่างที่ถูกสร้างโดยใช้ new จะต้องถูกทำลายโดยใช้ deleteเป็นการขอยกเลิกการใช้หน่วยความจำใน heap นอกจากนั้น ทุกสิ่งทุกอย่างที่ถูกสร้างโดยใช้ new[ ] จะต้องถูกทำลายโดยใช้ delete [ ] ตัวอย่างเช่น
1
2
pt = new myclass[3];
delete[] pt;
หลังจาก delete ไปแล้ว ควรกำหนดให้ค่าเป็น NULL 
1
2
3
4
delete mike;
mike = NULL;
delete nilgun;
nilgun = NULL;

ข้อระมัดระวังในการใช้งานตัวชี้

Heap Corruption

สิ่งที่โปรแกรมเมอร์ต้องระมัดระวังเมื่อมีการใช้ตัวชี้ คือ เมื่อมีการใช้ตัวชี้มากกว่าหนึ่งตัวชี้ไปยัง object ตัวเดียวกันหากภายหลังมีการลบตัว object ที่ถูกอ้างอิงนั้น แล้วตัวชี้ที่เหลือพยามเข้าเรียกใช้ข้อมูลที่ถูกลบไปแล้วจะทำให้เกิดข้อผิดพลาดได้  และเรียกข้อผิดพลาดในลักษณะนี้ว่า heap corruption เนื่องจากตัวชี้ที่เหลือพยามชี้ไปยังข้อมูลที่โปรแกรมไม่ได้จองไว้ (เนื่องจากได้ทำการคืนไปแล้วด้วยคำสั่ง delete)
1
2
3
4
5
6
char* ptr1;
char* ptr2;
ptr1 = new char('C');
ptr2 = ptr1;
delete ptr1;
cout << *ptr2;

Heap corruption

จากตัวอย่างนี้จะเห็นว่าตัวแปร ptr1 และ ptr2 ต่างชี้ไปยังตำแหน่งหน่วยความจำเดียวกันด้วยคำสั่ง ptr1 = new char('C'); และ ptr2=ptr1 จากนั้นได้ทำการคืนหน่วยความจำที่ ptr1 ได้ชี้ไว้ด้วยคำสั่ง delete ptr1; จากนั้นโปรแกรมเมอร์พยามแสดงผลข้อมูลที่อยู่ในตำแหน่งหน่วยความจำที่ได้คืนไปแล้วด้วยคำสั่ง cout << *ptr2; ทำให้เกิด heap corruption

Memory Leak 

ต้องตรวจสอบโค้ดไม่ให้เกิดหน่วยความจำรั่วไหล (Memory Leak) ตัวอย่างเช่นมีการจองหน่วยความจำใหม่ขณะที่ยังไม่มีการคืนหน่วยความจำเก่าที่จองไว้ดังโค้ดด้านล่างต่อไปนี้
1
2
3
4
5
int *list;
list = new int(25);
......
list = new int;
delete list;

memory leak

Memory leak

จากตัวอย่างนี้จะเห็นว่ามีการจองหน่วยความจำผ่านทางตัวชี้ list ซ้ำถึงสองครั้งโดยไม่มีการคืนหน่วยความจำก่อนดังนั้นเมื่อทำการใช้คำสั่ง delete list; จะเป็นการคืนหน่วยความจำที่จองไว้ครั้งล่าสุดเท่านั้นในขณะที่หน่วยความจำที่จองไว้ด้วยคำสั่ง list = new int(25); ไม่ได้คืนให้กับระบบแต่อย่างใด

***********************************************************************************************************************************************



Pointers in C++


Pointer is a variable in C++ that holds the address of another variable. They have data type just like variables, for example an integer type pointer can hold the address of an integer variable and an character type pointer can hold the address of char variable.

Syntax of pointer

data_type *pointer_name;
How to declare a pointer?
/* This pointer p can hold the address of an integer 
 * variable, here p is a pointer and var is just a
 * simple integer variable
 */
int *p, var
Assignment
As I mentioned above, an integer type pointer can hold the address of another int variable. Here we have an integer variable var and pointer p holds the address of var. To assign the address of variable to pointer we use ampersand symbol (&).
/* This is how you assign the address of another variable
 * to the pointer
 */
p = &var;
How to use it?
/ This will print the address of variable var
cout<<&var;    

/* This will also print the address of variable
 * var because the pointer p holds the address of var
 */
cout<<p;    

/* This will print the value of var, This is 
 * important, this is how we access the value of
 * variable through pointer
*/
cout<<*p; 

Example of Pointer

Lets take a simple example to understand what we discussed above.
#include <iostream>
using namespace std;
int main(){
   //Pointer declaration
   int *p, var=101;
 
   //Assignment
   p = &var;

   cout<<"Address of var: "<<&var<<endl;
   cout<<"Address of var: "<<p<<endl;
   cout<<"Address of p: "<<&p<<endl;
   cout<<"Value of var: "<<*p;
   return 0;
}
Output:
Address of var: 0x7fff5dfffc0c
Address of var: 0x7fff5dfffc0c
Address of p: 0x7fff5dfffc10
Value of var: 101

Pointer and arrays

While handling arrays with pointers you need to take care few things. First and very important point to note regarding arrays is that the array name alone represents the base address of array so while assigning the address of array to pointer don’t use ampersand sign(&). Do it like this:
Correct: Because arr represent the address of array.
p = arr;
Incorrect:
p = &arr;

Example: Traversing the array using Pointers

#include <iostream>
using namespace std;
int main(){
   //Pointer declaration
   int *p;
   //Array declaration
   int arr[]={1, 2, 3, 4, 5, 6};
   //Assignment
   p = arr;
   for(int i=0; i<6;i++){
     cout<<*p<<endl;
     //++ moves the pointer to next int position
     p++;
   }
   return 0;
}
Output:
1
2
3
4
5
6

How to increment pointer address and pointer’s value?

When we are accessing the value of a variable through pointer, sometimes we just need to increment or decrement the value of variable though it or we may need to move the pointer to next int position(just like we did above while working with arrays). The ++ operator is used for this purpose. One of the example of ++ operator we have seen above where we traversed the array using pointer by incrementing the pointer value using ++ operator. Lets see few more cases.
// Pointer moves to the next int position (as if it was an array)
p++; 
// Pointer moves to the next int position (as if it was an array)   
++p;   

/* All the following three cases are same they increment the value 
 * of variable that the pointer p points.
 */
++*p;   
++(*p); 
++*(p); 
*****************************************************************************************
*************************************
What is a Pointer?
The use of the "Address of" (&) and "Dereference" (*) Operator
How dereferencing a pointer takes on different meanings, depending on if the pointer is derefenced on the right or left-hand side of an assignment. 
Overview of how Pointers are really used in C++ programs.
******************************************************************************************************************************************
อธิบายประโยชน์ของพอยเตอร์ได้ดี
http://members.tripod.com/mt_kmitnb/Computer_Programming/POINTER.htm