Tag Archives: Con trỏ C/C++

Con trỏ trong C/C++

Con trỏ thực sự là một biến giữ địa chỉ. Tuy nhiên nó ẩn chứa rất nhiều “bí ẩn”!?! Ta cùng xem ví dụ sau:

01. short a = 5;
02. short* pshort;       // Khai báo một con trỏ kiểu short
03. unsigned long* plong; // Khai báo một con trỏ kiểu unsigned long
04. pshort = &a;          // Con trỏ pshort đang giữ địa chỉ của a
05. *pshort = 7;          // Dòng này đã thay đổi giá trị của a (bây giờ a = 7)
06. unsigned short A[5] = {0}; // Khai báo mảng A với năm phần tử
07. plong = (unsigned long*)&A[3];
08. *plong = 0xDEADBEEF;   // A[3] = 0xBEEF ~ 48879; A[4] = 0xDEAD ~ 57005;
/*
Dòng code 7, 8 khá đặc biệt! kiểu long có kích thước 4 byte mà kiểu short có kích thước 2 byte nên *plong tương đương một biến 4 byte bao trùm lên cả A[3] và A[4]
*/

Qua những dòng code trên bạn chắc cũng đã phần nào hiểu sơ về con trỏ!!! ^^

VOID
Bạn để ý thấy hầu như các con trỏ trên đều có kiểu cụ thể (int, short,…) Thế thì liệu có con trỏ nào khác mà không thuộc những kiểu dữ liệu ấy không?!? Xin thưa là có! Đó là con trỏ vô kiểu 🙂 (không thuộc kiểu nào hết ak!)

void*

Bạn nghĩ biến A[3] ngoài kiểu unsigned short còn có kiểu nào nữa không??? 🙂 Đó là kiểu void!!! Có thể bạn sẽ khá bất ngờ về điều này!

Biến con trỏ void có thể nhận địa chỉ của bất kì biến nào, có thể được gán bằng biến con trỏ tùy ý. Dựa vào đặc tính này bạn có thể viết những đoạn mã nguồn tổng quát có thể dùng lại cho nhiều kiểu dữ liệu khác nhau.

Bản thân kiểu void không xác định kích thước!!! Bạn nghĩ sizeof(void) = ??? 🙂 VÔ NGHĨA! Nhưng sizeof(void*) = 4 (Tùy vào công nghệ). Vì sao vậy? Đó là do con trỏ void* giữ địa chỉ bộ nhớ.
Ví dụ:

float a[5];
void *pvoid = a;
...

pvoid + 1, p[1], *p => Error!!!
Mọi thao tác đều phải ép kiểu!
*p => Phải là: *(float*)p

CON TRỎ HẰNG

Con trỏ trỏ đến vùng dữ liệu hằng

Vùng dữ liệu mà con trỏ đang trỏ đến không được phép sửa đổi nhưng bản thân biến con trỏ thì có thể thay đổi (có thể trỏ đến nơi khác, tăng giảm địa chỉ).

const char* pStr = “I love you…<3”;
// <=> char const* pStr = “I love you…<3”;
pStr[0] = ‘i’;             // Error! => Dữ liệu không thể đổi
pStr++;                      // OK
pStr = “I miss you!”;   // OK
//——————————-
const char* pChr;
char cStr[17] = “Have a nice day!”;
cStr[0] = ‘h’;        // OK
pChr = cStr;
pChr[0] = ‘H’;     // Error! => Ko thể thay đổi

Hằng con trỏ

Bản thân con trỏ bị gim vào 1 địa chỉ bộ nhớ và không thể trỏ đến vùng dữ liệu mới hay tăng giảm con trỏ. Điểm đặc biệt là vùng dữ liệu có thể thay đổi thông qua con trỏ.

char* const cp;
char cStr[] = "Have a nice day!";
cp = cStr;
cp[0] = 'h';    // OK
cp = "Have a nice night!";  // Error!
cp++;  // Error!

Hằng con trỏ đến vùng dữ liệu hằng

Đây là một con trỏ hằng. Nó không được phép thay đổi giá trị địa chỉ mà nó đang giữ và cũng không thể thay đổi vùng dữ liệu mà nó đang trỏ đến.

const char* const ccStr = "You are number one!";
// Chú ý có 2 chữ "const" gần nhau
ccStr[0] = 'y'; // => Error!
ccStr = "Good!"; // => Error!

Con trỏ hàm

Chức năng: giữ các hàm. Con trỏ hàm tạo điều kiện cho các Dev viết những đoạn code có khả năng tái sử dụng cao trong nhiều tình huống nhờ việc biến tấu các con trỏ hàm. Khi thay con trỏ hàm bằng những hàm cụ thể thì chương trình sẽ thực thi ứng với từng hàm cụ thể.
VD:

// Các hàm phép tính cơ bản
int Cong(int a, int b){ return a + b; }
int Tru(int a, int b){ return a - b; }
int Nhan(int a, int b){ return a * b; }
// Hàm chia lấy phần nguyên
int ChiaLayNguyen(int a, int b){ return a / b; }
// Hàm chia lấy phần dư
int ChiaLayDu(int a, int b) { return a % b; }
int TinhToan(int a, int b, int (*ConTroHam)(int, int))
{ return ConTroHam(a, b); }
//----------------------------------------------------
// MAIN
int main()
{
    // Sử dụng
    int a = 10, b = 3;
    cout << a << " + " << b << " = "
         << TinhToan(a, b, &Cong) << endl;

    cout << a << " - " << b << " = "
         << TinhToan(a, b, &Tru) << endl;

    cout << a << " * " << b << " = "
         << TinhToan(a, b, &Nhan) << endl;

    cout << a << " / " << b << " = "
         << TinhToan(a, b, &ChiaLayNguyen) << endl;

    cout << a << " % " << b << " = "
         << TinhToan(a, b, &ChiaLayDu) << endl;

    return 0;
}
Advertisements