Phạm vi biến (Scope)
Phạm vi (scope) của một biến là vùng code mà biến đó có thể được truy cập. Hiểu rõ scope giúp tránh những lỗi khó phát hiện liên quan đến biến “biến mất” hoặc bị trùng tên ngoài ý muốn.
Phạm vi khối lệnh (Block scope)
Phần tiêu đề “Phạm vi khối lệnh (Block scope)”Một biến khai báo bên trong {} chỉ tồn tại bên trong khối lệnh đó:
#include <iostream>
int main() { { int x = 10; std::cout << x << std::endl; // 10 - OK, x đang trong phạm vi } // std::cout << x << std::endl; // LỖI! x đã ra khỏi phạm vi (scope), không còn tồn tại
return 0;}Điều này áp dụng cho mọi khối lệnh: if, for, while, hay thân hàm:
#include <iostream>
int main() { for (int i = 0; i < 3; i++) { int squared = i * i; // squared chỉ tồn tại trong MỖI lần lặp std::cout << squared << " "; } // std::cout << i << std::endl; // LỖI! i chỉ tồn tại trong for // std::cout << squared << std::endl; // LỖI! squared cũng vậy
return 0;}Biến cục bộ (Local variable) che khuất biến ngoài
Phần tiêu đề “Biến cục bộ (Local variable) che khuất biến ngoài”Một biến khai báo trong phạm vi hẹp hơn có thể che khuất (shadow) biến cùng tên ở phạm vi rộng hơn:
#include <iostream>
int x = 100; // Biến toàn cục (global)
int main() { int x = 5; // Biến cục bộ (local), CHE KHUẤT biến toàn cục cùng tên std::cout << x << std::endl; // 5 (biến cục bộ được ưu tiên)
{ int x = 1; // Che khuất thêm một lớp nữa std::cout << x << std::endl; // 1 }
std::cout << x << std::endl; // 5 (trở lại biến cục bộ ở scope ngoài)
return 0;}Việc đặt tên trùng như trên hoàn toàn hợp lệ về mặt cú pháp, nhưng nên tránh vì dễ gây nhầm lẫn khi đọc code.
Truy cập biến toàn cục khi bị che khuất
Phần tiêu đề “Truy cập biến toàn cục khi bị che khuất”Dùng toán tử phạm vi :: (không có gì đứng trước) để truy cập rõ ràng biến toàn cục, ngay cả khi nó đang bị che khuất:
#include <iostream>
int x = 100;
int main() { int x = 5; std::cout << x << std::endl; // 5 (biến cục bộ) std::cout << ::x << std::endl; // 100 (biến toàn cục, dùng :: để chỉ rõ)
return 0;}Biến toàn cục (Global variable)
Phần tiêu đề “Biến toàn cục (Global variable)”Biến khai báo bên ngoài mọi hàm có thể được truy cập từ bất kỳ đâu trong file:
#include <iostream>
int counter = 0; // Biến toàn cục
void increase() { counter++; // Truy cập và thay đổi biến toàn cục trực tiếp}
int main() { increase(); increase(); std::cout << counter << std::endl; // 2
return 0;}Dùng biến toàn cục quá nhiều thường được xem là thực hành không tốt (bad practice), vì nó khiến code khó theo dõi (bất kỳ hàm nào cũng có thể âm thầm thay đổi trạng thái toàn cục) và khó kiểm thử.
Biến static bên trong hàm: “nhớ” giá trị giữa các lần gọi
Phần tiêu đề “Biến static bên trong hàm: “nhớ” giá trị giữa các lần gọi”Từ khóa static khi dùng bên trong một hàm tạo ra một biến chỉ được khởi tạo một lần duy nhất, và giữ nguyên giá trị giữa các lần gọi hàm:
#include <iostream>
void count_calls() { static int count = 0; // Chỉ khởi tạo MỘT LẦN, dù hàm được gọi nhiều lần count++; std::cout << "Da goi ham nay " << count << " lan" << std::endl;}
int main() { count_calls(); // Da goi ham nay 1 lan count_calls(); // Da goi ham nay 2 lan count_calls(); // Da goi ham nay 3 lan
return 0;}Khác với biến cục bộ thông thường (bị hủy và tạo lại mỗi lần gọi hàm), biến static cục bộ tồn tại suốt vòng đời chương trình, nhưng vẫn chỉ có thể truy cập được từ bên trong hàm đó.
Tổng kết
Phần tiêu đề “Tổng kết”- Biến khai báo trong
{}chỉ tồn tại bên trong khối lệnh đó (block scope) - Biến cục bộ có thể che khuất biến toàn cục cùng tên - dùng
::để truy cập biến toàn cục khi cần - Biến toàn cục truy cập được từ mọi nơi, nhưng nên hạn chế dùng vì dễ gây khó kiểm soát code
- Biến
staticbên trong hàm chỉ khởi tạo một lần và giữ nguyên giá trị giữa các lần gọi hàm