[Học lập trình C++] Chương 1: 1.3 Làm quen với biến, khởi tạo và phép gán

1.3 Làm quen với biến, khởi tạo và phép gán
Biến
Một câu lệnh như x = 5; nhìn có vẻ như đầy đủ. Như bạn nghĩ, chúng ta đang giá trị 5 vào x. Nhưng chính xác thì x là gì? X là một biến.
Một biến trong C++ là tên của một phần bộ nhớ mà có thể được dùng để lưu trữ thông tin. Bạn có thể nghĩ về một biến giống như một hộp thư, hoặc một tủ chứa, nơi mà chúng ta có thể lưu trữ hoặc lấy thông tin. Tất cả các máy tính đều có bộ nhớ, được gọi là RAM (random access memory), đó có sẵn cho chương trình dùng. Khi một biến được định nghĩa, một phần của bộ nhớ đó được cấp riêng cho biến đó.
Trong phần này, chúng ta chỉ quan tâm đến biến integer. Một biến integer là một số nguyên, ví dụ 1, 2, 3, 4, -1, -12 hoặc 16. Một biến integer là một biến mà giữ giá trị integer.
Để định nghĩa một biến, thông thường chúng ta sử dụng câu lệnh khai báo. Ví dụ:
Int x;
Khi câu lệnh này được thực thi bởi CPU, một phần của bộ nhớ từ RAM sẽ được cấp. Ví dụ, một biến được gán một địa chỉ là 140. Bất cứ khi nào chương trình nhìn biến x trong một biểu thức hoặc câu lệnh, nó biết rằng nó nên xem ở địa chỉ bộ nhớ 140 để lấy giá trị.
Một trong những hoạt động phổ biến nhất khi làm việc với biến đó là phép gán. Để làm điều này, chúng ta sử dụng toán tử gán, được thực hiện bằng dấu =. Ví dụ:
X = 5;
Khi CPU thực thi dòng lệnh này, nó hiểu rằng “Đặt giá trị của 5 vào trong địa chỉ bộ nhớ 140”. Trong chương trình của chúng ta, chúng ta có thể in những giá trị đó ra màn hình nhờ câu lệnh std::out:
Std::cout << x;
l-values và r-values
trong C++, biến là một loại l-value. L-value là một giá trị mà có một địa chỉ (trong bộ nhớ). Bởi vì tất cả các biến đều có địa chỉ, tất cả các biến đều là l-values. Tên l-value xuất phát từ việc nó nằm bên trái của toán tử gán. Khi chúng ta thực hiện một phép gán, phía bên trái phải là một l-value. Do đó, một câu lệnh như 5 = 6; sẽ bị lỗi, bởi vì 5 không phải là một l-value. Giá trị của 5 không có địa chỉ bộ nhớ nào, và do đó không có gì có thể được gán vào nó cả. 5 nghĩa là 5, và giá trị của nó không thể được gán lại. khi một l-value có một giá trị để gán vào, giá trị hiện thời tại  địa chỉ đó bị ghi đè lên.
Trái ngược với l-values là r-values. Một r-value liên quan đến bất kì giá trị nào có thể được gán cho một l-value. R-value luôn luôn được tính toán ra một giá trị đơn.
Đây là một ví dụ  cho thấy một vài câu lệnh gán, thể hiện việc tính toán của r-value:
int y;      // define y as an integer variable
y = 4;      // 4 evaluates to 4, which is then assigned to y
y = 2 + 5;  // 2 + 5 evaluates to 7, which is then assigned to y

int x;      // define x as an integer variable
x = y;      // y evaluates to 7 (from before), which is then assigned to x.
x = x;      // x evaluates to 7, which is then assigned to x (useless!)
x = x + 1;  // x + 1 evaluates to 8, which is then assigned to x.

Hãy khảo sát một cách chi tiết hơn về phép gán cuối cùng phía trên, vì nó hơi rối:
x = x + 1;
Trong câu lệnh này, biến x được sử dụng trong hai ngữ cảnh khác nhau. Tại bên trái của toán tử gán, x được sử dụng như một l-value (biến có địa chỉ bộ nhớ). Tại bên phải của toán tử gán, x được sử dụng như một r-value, và sẽ được tính toán để tạo ra một giá trị. Khi C++ tính toán câu lệnh trên, nó sẽ tính như sau:
x = 7 + 1;
Một cách hiển nhiên rằng C++ sẽ gán giá trị 8 ngược vào biến x.
Lập trình viên không có khuynh hướng nói về l-value hoặc r-value nhiều, vì vậy nó không quan trọng làm để nhớ phần này. Chìa khóa nằm ở chỗ phía bên trái của toán tử gán, bạn phải có một cái gì đó đại diện cho địa chỉ bộ nhớ. Mọi thứ nằm bên phải của toán tử gán sẽ được tính toán để tạo ra một giá trị.
Khởi tạo và phép gán
C++ hỗ trợ hai khái niệm liên quan mà lập trình viên mới thường lẫn lộn: phép gán và khởi tạo trị.
Sau khi một biến được định nghĩa, một giá trị có thể được gán vào nó thông qua toán tử gán.
int x; // this is a variable definition
x = 5; // assign the value 5 to variable x
C++ sẽ để cho bạn vừa định nghĩa vừa đặt một giá trị ban đầu vào nó trong cùng một bước. Đây gọi là sử khởi tạo.
int x = 5; // initialize variable x with the value 5
Một biến chỉ có thể được khởi tạo khi nó được định nghĩa. Mặc dù hai khái niệm này tương tự nhau, và có thể thường được dùng để có được một kết quả tương đương, chúng ta sẽ xem xét những trường hợp này trong những bài học kế tiếp nơi có một vài kiểu của biến yêu cầu một giá trị khởi tạo, hoặc không cho phép gán. Bởi những lý do này, nên nó rất hữu ích khi phân biệt ngay bây giờ.
Biến không được khởi tạo
Không giống một vài ngôn ngữ lập trình, C/C++ không khởi tạo giá trị cho biến một cách tự động (vì lí do hiệu suất). Do đó khi một biến được gán một địa chỉ bộ nhớ bởi trình biên dịch giá trị mặc định của biến là những giá trị rác có sẵn trong địa chỉ bộ nhớ đó. Một biến không được gán giá trị được gọi là một biến chưa khởi tạo.
Chú ý: một vài trình biên dịch, giống như visual studio sẽ khởi tạo nội dung của bộ nhớ khi bạn sử dụng cấu hình debug.
Biến chưa khởi tạo có thể tạo ra một số kết quả thú vị:
// #include "stdafx.h" // Uncomment if Visual Studio user
#include <iostream>

int main()
{
    // define an integer variable named x
    int x;
    
    // print the value of x to the screen (dangerous, because x is uninitialized)
    std::cout << x;

    return 0;
}

Trong trường hợp này, máy tính sẽ gán một địa chỉ bộ nhớ chưa sử dụng cho x. Nó sau đó gửi giá trị trong bộ nhớ này ra cout. Nhưng giá trị gì sẽ được in ra? Câu trả lời là không ai biết, và câu trả lời có thể thay đổi mỗi khi bạn chạy chương trình.
Sử dụng biến chưa khởi tạo là một trong những sai lầm phổ biến nhất mà người mới học lập trình mắc phải, và không may, nó cũng là một trong những thử thách để debug (bởi vì chương trình có thể chạy tốt cho dù biến được khởi tạo hay chưa).
Thật may là hầu hết các trình biên dịch hiện đại sẽ in ra thông báo cảnh báo tại thời điểm biên dịch nếu chúng có thể phát hiện một biến mà sử dụng không được khởi tạo giá trị. Ví dụ, chương trình trên:
c:vc2005projectstesttesttest.cpp(11) : warning C4700: uninitialized local variable 'x' used

Nguyên tắc tốt nhất là nên khởi tạo một giá trị cho biến. Điều này chắc chắn biến của bạn luôn luôn có một giá trị, làm cho nó dễ dang debug nếu có một sai sót ở một nơi nào đó.

Nguồn: learncpp.com

Nhận xét

Bài đăng phổ biến