Nếu bạn đang theo dõi loạt bài hướng dẫn lập trình C của chúng tôi, bạn sẽ biết đến khái niệm biến. Trong khi chúng ta đã thảo luận về những điều cơ bản của biến, vẫn còn một khía cạnh quan trọng khác liên quan đến biến mà chúng ta sẽ thảo luận ở đây: phạm vi của biến.
Chúng ta hãy bắt đầu với mã hoán đổi giá trị mà chúng ta đã sử dụng trong một trong các hướng dẫn trước đây của mình:
Ở đây, trong đoạn mã này, các biến 'val1' và 'val2' có phạm vi cục bộ, nghĩa là chúng hoạt động khi hàm 'swap' được gọi và chúng chết ngay sau khi lệnh gọi đến 'swap' kết thúc. Bạn không thể truy cập 'val1' và 'val2' trước hoặc sau lệnh gọi đến hàm 'swap'. Tương tự như vậy, phạm vi của các biến 'a' và 'b' cũng là cục bộ - cục bộ đối với hàm 'main'.
Lưu ý rằng các biến phạm vi cục bộ này cũng được gọi là biến tự động.
Bây giờ, trong khi các biến có phạm vi cục bộ bị giới hạn trong khối mà chúng được khai báo, thì có một loại biến khác có phạm vi là toàn cục. Như tên gọi của nó, các biến phạm vi toàn cục có thể được sử dụng trên các hàm. Ví dụ, biến 'var' là một biến số nguyên toàn cục và có thể được sử dụng trong cả hàm 'main' và 'swap'.
Theo mặc định, giá trị '0' được gán cho các biến toàn cục. Nhưng điều đó không đúng với các biến cục bộ - bạn cần gán giá trị cho chúng khi chúng được định nghĩa, nếu không chúng sẽ giữ giá trị rác. Ví dụ, trong chương trình sau:
Có khả năng cao là bạn sẽ nhận được giá trị khác không cho 'a'. Mặt khác, 'var' sẽ luôn bằng 0 khi bắt đầu.
Tiếp theo, có thể có các biến toàn cục và cục bộ cùng tên không? Câu trả lời là có. Được rồi, vậy thì đoạn mã sau sẽ tạo ra kết quả gì ở đầu ra:
Ồ, đầu ra sẽ là '10' trong cả hai trường hợp. Lý do là, biến cục bộ 'var' sẽ ghi đè lên 'var' toàn cục. Vậy câu hỏi hợp lý tiếp theo là, làm thế nào để truy cập 'var' toàn cục bên trong 'main' trong trường hợp này? Thật đáng buồn, câu trả lời là KHÔNG. Trên thực tế, bạn nên tránh rơi vào những tình huống như thế này khi làm việc với ngôn ngữ C.
Tiếp theo là khái niệm về biến 'extern'. Nói một cách dễ hiểu, bằng cách sử dụng từ khóa 'extern' với bất kỳ khai báo biến nào, bạn đang cho trình biên dịch biết rằng biến này đã được khai báo/xác định ở đâu đó khác và chúng ta chỉ sử dụng nó ở đây. Ví dụ, trong đoạn mã sau, trình biên dịch không biết 'var' tồn tại khi nó cố gắng biên dịch câu lệnh printf bên trong hàm main.
Đó là lý do tại sao bạn nhận được lỗi như sau trong quá trình biên dịch:
Nhưng nếu bạn khai báo 'var' là extern ở đây, bạn sẽ thấy mọi thứ hoạt động tốt. Đó là vì trình biên dịch cuối cùng sẽ đến được khai báo 'var' ban đầu.
Và bạn nhận được đầu ra chính xác:
Vậy thì đây là cách extern hoạt động. Các biến extern thường được sử dụng khi chương trình/dự án của bạn được chia thành nhiều tệp mã nguồn và bạn muốn, chẳng hạn, sử dụng trong 'file1', một biến được định nghĩa trong 'file2'.
Và cuối cùng, khi chúng ta đang thảo luận về phạm vi biến, sẽ tốt hơn nếu chúng ta cũng thảo luận về các biến 'tĩnh' ở đây. Biến tĩnh là đặc biệt theo nghĩa chúng vẫn giữ nguyên giá trị của mình ngay cả sau khi ra khỏi phạm vi. Điều này có nghĩa là chúng chỉ được khởi tạo một lần, tức là lần đầu tiên.
Sau đây là một đoạn mã sử dụng biến tĩnh để đếm số lần một hàm được gọi.
Đây là kết quả:
Vì vậy, bạn có thể thấy, biến 'counter' vẫn giữ nguyên giá trị ngay cả sau khi ra khỏi phạm vi. Giống như biến toàn cục, biến tĩnh cũng có giá trị mặc định là '0'.
Trong hướng dẫn này, chúng ta đã thảo luận về một số khái niệm quan trọng, tất cả đều liên quan đến phạm vi của biến trong ngôn ngữ lập trình C. Đừng quên tạo chương trình của riêng bạn để hiểu rõ hơn về sự khác biệt giữa biến extern, static, global và local. Và như mọi khi, trong trường hợp có bất kỳ nghi ngờ hoặc thắc mắc nào, hãy để lại bình luận bên dưới.
Chúng ta hãy bắt đầu với mã hoán đổi giá trị mà chúng ta đã sử dụng trong một trong các hướng dẫn trước đây của mình:
Mã:
#include
void swap (int val1, int val2)
{
int temp = 0;
temp = val1;
val1 = val2;
val2 = temp;
printf("\nGiá trị hoán đổi là: %d và %d", val1,val2);
}
int main()
{
int a=0, b=0;
printf("Nhập hai giá trị số nguyên\n");
scanf("%d %d",&a,&b);
printf("Giá trị nhập vào là: %d và %d", a,b);
swap(a,b);
return 0;
}
Lưu ý rằng các biến phạm vi cục bộ này cũng được gọi là biến tự động.
Bây giờ, trong khi các biến có phạm vi cục bộ bị giới hạn trong khối mà chúng được khai báo, thì có một loại biến khác có phạm vi là toàn cục. Như tên gọi của nó, các biến phạm vi toàn cục có thể được sử dụng trên các hàm. Ví dụ, biến 'var' là một biến số nguyên toàn cục và có thể được sử dụng trong cả hàm 'main' và 'swap'.
Mã:
#include
int var;
void swap (int val1, int val2)
{
int temp = 0;
temp = val1;
val1 = val2;
val2 = temp;
printf("\nCác giá trị được hoán đổi là: %d và %d", val1,val2);
}
int main()
{
int a=0, b=0;
printf("Nhập hai giá trị số nguyên\n");
scanf("%d %d",&a,&b);
printf("Các giá trị đã nhập là: %d và %d", a,b);
swap(a,b);
return 0;
}
Mã:
#include
int var;
int main()
{
int a;
printf("Biến cục bộ 'a' hiện giữ: %d", a);
printf("\n Biến toàn cục var hiện giữ: %d", var);
return 0;
}
Tiếp theo, có thể có các biến toàn cục và cục bộ cùng tên không? Câu trả lời là có. Được rồi, vậy thì đoạn mã sau sẽ tạo ra kết quả gì ở đầu ra:
Mã:
#include
int var = 5;
int main()
{
int var = 10;
printf("Biến cục bộ 'a' hiện giữ: %d", var);
printf("\n Biến toàn cục var hiện giữ: %d", var);
return 0;
}
Tiếp theo là khái niệm về biến 'extern'. Nói một cách dễ hiểu, bằng cách sử dụng từ khóa 'extern' với bất kỳ khai báo biến nào, bạn đang cho trình biên dịch biết rằng biến này đã được khai báo/xác định ở đâu đó khác và chúng ta chỉ sử dụng nó ở đây. Ví dụ, trong đoạn mã sau, trình biên dịch không biết 'var' tồn tại khi nó cố gắng biên dịch câu lệnh printf bên trong hàm main.
Mã:
#include
int main()
{
printf("\n Biến toàn cục var hiện giữ: %d", var);
return 0;
}
int var = 5;
Mã:
main.c: Trong hàm 'main':
main.c:14:58: lỗi: 'var' chưa được khai báo (lần đầu tiên sử dụng trong hàm này)
printf("\n Biến toàn cục var hiện giữ: %d", var);
^
main.c:14:58: lưu ý: mỗi định danh chưa được khai báo chỉ được báo cáo một lần cho mỗi hàm mà nó xuất hiện in
Mã:
#include
int main()
{
extern int var;
printf("\n Biến toàn cục var hiện giữ: %d", var);
return 0;
}
int var = 5;
Mã:
Biến toàn cục var hiện giữ: 5
Và cuối cùng, khi chúng ta đang thảo luận về phạm vi biến, sẽ tốt hơn nếu chúng ta cũng thảo luận về các biến 'tĩnh' ở đây. Biến tĩnh là đặc biệt theo nghĩa chúng vẫn giữ nguyên giá trị của mình ngay cả sau khi ra khỏi phạm vi. Điều này có nghĩa là chúng chỉ được khởi tạo một lần, tức là lần đầu tiên.
Mã:
static int counter
Mã:
#include
int swap (int val1, int val2)
{
static int counter = 1;
int temp = 0;
temp = val1;
val1 = val2;
val2 = temp;
printf("\n Hàm được gọi %d lần\n", counter);
counter++;
}
int main()
{
int a=9, b=4;
swap(a,b);
swap(a,b);
swap(a,b);
return 0;
}
Mã:
Hàm được gọi 1 lần
Hàm được gọi 2 lần
Hàm được gọi 3 lần
Trong hướng dẫn này, chúng ta đã thảo luận về một số khái niệm quan trọng, tất cả đều liên quan đến phạm vi của biến trong ngôn ngữ lập trình C. Đừng quên tạo chương trình của riêng bạn để hiểu rõ hơn về sự khác biệt giữa biến extern, static, global và local. Và như mọi khi, trong trường hợp có bất kỳ nghi ngờ hoặc thắc mắc nào, hãy để lại bình luận bên dưới.