Trong bài – Giới thiệu về phạm vi biến cục bộ, chúng ta đã giới thiệu về biến cục bộ, là những biến được định nghĩa bên trong một hàm (bao gồm cả các tham số của hàm).

Nó chỉ ra rằng C ++ thực sự không có một thuộc tính duy nhất xác định một biến là một biến cục bộ. Thay vào đó, các biến cục bộ có một số thuộc tính khác nhau giúp phân biệt cách các biến cục bộ hoạt động với các loại biến (không cục bộ) khác. Chúng ta sẽ khám phá các thuộc tính này trong bài học này và các bài học sắp tới, cũng như một số chủ đề lưu ý liên quan đến biến cục bộ khác.

1. Các biến cục bộ có phạm vi trong block

Phạm vi của để xác định nơi có thể truy cập các tên định danh trong code nguồn. Phạm vi là thuộc tính thời gian biên dịch.

Các biến cục bộ có phạm vi trong khối(block), có nghĩa là chúng nằm trong phạm vi từ điểm định nghĩa của chúng đến cuối khối mà chúng được xác định bên trong.

int main()
{
    int i { 5 }; // i enters scope here
    double d { 4.0 }; // d enters scope here
 
    return 0;
} // i and d go out of scope here

Mặc dù các tham số hàm không được định nghĩa bên trong thân hàm, nhưng đối với các hàm điển hình, chúng có thể được coi là một phần của phạm vi của khối thân hàm.

int max(int x, int y) // x and y enter scope here
{
    // assign the greater of x or y to max
    int max{ (x > y) ? x : y }; // max enters scope here
 
    return max;
} // x, y, and max leave scope here

Trường hợp ngoại lệ dành cho việc xử lý ngoại lệ cấp hàm (chúng ta sẽ trình bày trong bài  – Khối thử hàm).

2. Tất cả các tên biến trong một phạm vi phải là duy nhất

Tên biến phải là duy nhất trong một phạm vi nhất định, nếu không mọi tham chiếu đến tên sẽ không rõ ràng. Hãy xem xét chương trình sau:

void someFunction(int x)
{
    int x{}; // compilation failure due to name collision with function parameter
}
 
int main()
{
    return 0;
}

Chương trình trên không biên dịch vì biến x được xác định bên trong thân hàm và tham số hàm x có cùng tên và cả hai đều nằm trong cùng một phạm vi khối.

3. Các biến cục bộ có thời lượng lưu trữ tự động

Thời lượng lưu trữ của một biến (thường chỉ được gọi là thời lượng) xác định những quy tắc nào chi phối thời gian và cách thức một biến sẽ được tạo và hủy. Trong hầu hết các trường hợp, thời lượng lưu trữ của một biến xác định trực tiếp thời gian tồn tại của nó.

Ví dụ: các biến cục bộ có thời lượng lưu trữ tự động, có nghĩa là chúng được tạo tại điểm khai báo và bị hủy ở cuối khối mà chúng được định nghĩa. Ví dụ:

int main()
{
    int i { 5 }; // i created and initialized here
    double d { 4.0 }; // d created and initialized here
 
    return 0;
} // i and d are destroyed here

Vì lý do này, các biến cục bộ đôi khi được gọi là biến tự động.

4. Biến cục bộ trong các khối lồng nhau

Các biến cục bộ có thể được định nghĩa bên trong các khối lồng nhau. Điều này hoạt động giống hệt với các biến cục bộ trong các khối nội dung hàm:

int main() // outer block
{
    int x { 5 }; // x enters scope and is created here
 
    { // nested block
        int y { 7 }; // y enters scope and is created here
    } // y goes out of scope and is destroyed here
 
    // y can not be used here because it is out of scope in this block
 
    return 0;
} // x goes out of scope and is destroyed here

Trong ví dụ trên, biến y được định nghĩa bên trong một khối lồng nhau. Phạm vi của nó bị giới hạn từ điểm định nghĩa đến cuối khối lồng nhau và thời gian tồn tại của nó là như nhau. Bởi vì phạm vi của biến y được giới hạn trong khối bên trong mà nó được xác định, nó không thể truy cập được ở bất kỳ đâu trong khối bên ngoài.

Lưu ý rằng các khối lồng nhau được coi là một phần của phạm vi của khối bên ngoài mà chúng được xác định. Do đó, các biến được xác định trong khối bên ngoài có thể được nhìn thấy bên trong một khối lồng nhau:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

#include <iostream>
 
int main()
{ // outer block
 
    int x { 5 }; // x enters scope and is created here
 
    { // nested block
        int y { 7 }; // y enters scope and is created here
 
        // x and y are both in scope here
        std::cout << x << " + " << y << " = " << x + y << '\n';
    } // y goes out of scope and is destroyed here
 
    // y can not be used here because it is out of scope in this block
 
    return 0;
} // x goes out of scope and is destroyed here

5. Các biến cục bộ không có liên kết

Định danh có một thuộc tính khác có tên là liên kết. Liên kết của số nhận dạng xác định xem các khai báo khác của tên đó có tham chiếu đến cùng một đối tượng hay không.

Các biến cục bộ không có liên kết, có nghĩa là mỗi khai báo tham chiếu đến một đối tượng duy nhất. Ví dụ:

int main()
{
    int x { 2 }; // local variable, no linkage
 
    {
        int x { 3 }; // this identifier x refers to a different object than the previous x
    }
 
    return 0;
}

Phạm vi và liên kết có thể hơi giống nhau. Tuy nhiên, phạm vi xác định nơi có thể thấy và sử dụng một khai báo duy nhất. Liên kết xác định xem nhiều khai báo có tham chiếu đến cùng một đối tượng hay không.

Liên kết không thú vị lắm trong bối cảnh của các biến cục bộ, nhưng chúng ta sẽ nói về nó nhiều hơn trong một vài bài học tiếp theo.

Các biến nên được xác định trong phạm vi hạn chế nhất

Nếu một biến chỉ được sử dụng trong một khối lồng nhau, thì nó phải được định nghĩa bên trong khối lồng nhau đó:

#include <iostream>
 
int main()
{
    // do not define y here
 
    {
        // y is only used inside this block, so define it here
        int y { 5 };
        std::cout << y << '\n';
    }
 
    // otherwise y could still be used here, where it's not needed
 
    return 0;
}

Bằng cách giới hạn phạm vi của một biến, bạn giảm độ phức tạp của chương trình vì số lượng biến hoạt động được giảm xuống. Hơn nữa, nó giúp bạn dễ dàng xem các biến được sử dụng (hoặc không được sử dụng) ở đâu. Một biến được xác định bên trong một khối chỉ có thể được sử dụng trong khối đó (hoặc các khối lồng nhau). Điều này có thể làm cho chương trình dễ hiểu hơn.

Nếu một biến là cần thiết trong một khối bên ngoài, thì nó cần được khai báo trong khối bên ngoài:

#include <iostream>
 
int main()
{
    int y { 5 }; // we're declaring y here because we need it in this outer block later
 
    {
        int x{};
        std::cin >> x;
 
        // if we declared y here, immediately before its actual first use...
        if (x == 4)
            y = 4;
    } // ... it would be destroyed here
 
    std::cout << y; // and we need y to exist here
 
    return 0;
}

Ví dụ trên cho thấy một trong những trường hợp hiếm hoi mà bạn có thể cần phải khai báo một biến trước lần sử dụng đầu tiên.

Các developer mới đôi khi tự hỏi liệu có nên tạo một khối lồng nhau chỉ để cố ý giới hạn phạm vi của một biến (và buộc biến nó ra khỏi phạm vi / bị hủy sớm). Làm như vậy làm cho biến đó đơn giản hơn, nhưng kết quả là hàm tổng thể trở nên dài hơn và phức tạp hơn. Sự đánh đổi nói chung là không đáng. Nếu việc tạo một khối lồng nhau có vẻ hữu ích để cố ý giới hạn phạm vi của một đoạn code, thì đoạn code đó có thể tốt hơn nếu đặt vào một hàm riêng.

Ban nên

Xác định các biến trong phạm vi hiện có hạn chế nhất. Tránh tạo các khối mới có mục đích duy nhất là giới hạn phạm vi của các biến.

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!