Khi bắt đầu tìm hiểu về ngôn ngữ lập trình C, việc nắm vững các khái niệm cơ bản về cách máy tính quản lý bộ nhớ, cũng như cách khai báo và sử dụng biến và hằng là vô cùng quan trọng. Bài viết này sẽ đi sâu vào những yếu tố nền tảng đó.
I. Bộ Nhớ Máy Tính
Bộ nhớ máy tính là một thành phần phần cứng thiết yếu, chịu trách nhiệm lưu trữ dữ liệu và các chương trình mà CPU cần truy cập. Để quản lý không gian nhớ một cách hiệu quả, hệ thống đã chuẩn hóa các đơn vị đo lường và cơ chế địa chỉ.
1. Các Đơn Vị Đo Lường Bộ Nhớ
Dung lượng bộ nhớ được đo bằng các đơn vị tiêu chuẩn, với đơn vị nhỏ nhất là bit và đơn vị cơ bản nhất là byte. Dưới đây là cách quy đổi phổ biến:
- 1 Byte (B) = 8 bit
- 1 Kilobyte (KB) = 1024 Bytes
- 1 Megabyte (MB) = 1024 Kilobytes
- 1 Gigabyte (GB) = 1024 Megabytes
- 1 Terabyte (TB) = 1024 Gigabytes
Trong thực tế, các đơn vị lớn hơn như Petabyte (PB), Exabyte (EB) cũng tồn tại nhưng ít được nhắc đến trong bối cảnh lập trình cơ bản.
2. Địa Chỉ Bộ Nhớ
Để CPU có thể đọc và ghi dữ liệu vào bộ nhớ, toàn bộ không gian bộ nhớ được chia thành các ô nhỏ, mỗi ô có kích thước 1 byte. Mỗi ô nhớ này được gán một "địa chỉ" duy nhất, tương tự như số nhà trên một con phố. Khi chương trình cần truy cập một vị trí dữ liệu cụ thể, nó sẽ sử dụng địa chỉ này để định vị ô nhớ tương ứng.
Các địa chỉ bộ nhớ thường được biểu diễn dưới dạng số thập lục phân (hexadecimal) để dễ đọc hơn so với chuỗi nhị phân dài. Ví dụ, trên một hệ thống 32-bit, địa chỉ bộ nhớ có thể là một số 32-bit, được rút gọn thành 8 ký tự thập lục phân (ví dụ: 0x0000FF1C).
II. Biến và Hằng Số
1. Biến
Trong lập trình C, một biến là một tên gọi (identifier) đại diện cho một vùng nhớ trong RAM dùng để lưu trữ dữ liệu. Vùng nhớ này có thể bao gồm một hoặc nhiều byte tùy thuộc vào kiểu dữ liệu của biến. Tên biến cho phép chúng ta tham chiếu đến giá trị được lưu trữ trong vùng nhớ đó một cách dễ dàng, thay vì phải nhớ địa chỉ bộ nhớ phức tạp.
2. Các Kiểu Dữ Liệu Cơ Bản của Biến
Cung cấp cho chương trình khả năng làm việc với nhiều loại dữ liệu khác nhau, C hỗ trợ một số kiểu dữ liệu cơ bản. Dưới đây là một số kiểu phổ biến cùng với kích thước bộ nhớ (thường thấy trên hệ thống 32-bit hoặc 64-bit):
| Kiểu dữ liệu | Mô tả | Kích thước (byte) | Ví dụ giá trị |
|---|---|---|---|
char |
Ký tự hoặc số nguyên nhỏ | 1 | 'A', 'z', 97 |
short |
Số nguyên ngắn | 2 | -32768 đến 32767 |
int |
Số nguyên (phổ biến) | 4 | -2,147,483,648 đến 2,147,483,647 |
long |
Số nguyên dài | 4 hoặc 8 (phụ thuộc hệ thống) | Tùy thuộc kích thước |
long long |
Số nguyên cực dài | 8 | Rất lớn |
unsigned int |
Số nguyên không dấu | 4 | 0 đến 4,294,967,295 |
float |
Số thực dấu phẩy động độ chính xác đơn | 4 | 3.14f, -0.5f |
double |
Số thực dấu phẩy động độ chính xác kép | 8 | 3.14159, 1.0e-5 |
_Bool (hoặc bool với <stdbool.h>) |
Giá trị boolean (true/false) | 1 | true, false (hoặc 1, 0) |
Khi bạn khai báo một biến, ví dụ int soLuong;, trình biên dịch sẽ dành ra một vùng nhớ có kích thước phù hợp (ví dụ 4 byte cho int) trong RAM để lưu trữ giá trị của soLuong.
3. Quy Tắc Đặt Tên Biến
Việc đặt tên biến trong C cần tuân thủ một số quy tắc:
- Tên biến có thể chứa các chữ cái (hoa và thường), chữ số và dấu gạch dưới (
_). - Tên biến phải bắt đầu bằng một chữ cái hoặc dấu gạch dưới (
_), không được bắt đầu bằng chữ số. - Ngôn ngữ C phân biệt chữ hoa và chữ thường (case-sensitive). Ví dụ,
tenBienvàTenBienlà hai biến khác nhau. - Tên biến không được trùng với các từ khóa dành riêng của C (ví dụ:
int,float,return). - Nên đặt tên biến có ý nghĩa và dễ hiểu để mã nguồn dễ đọc hơn.
4. Gán Giá Trị Cho Biến
Có hai cách chính để gán giá trị cho biến:
a) Khai báo biến và gán giá trị sau
Đầu tiên, bạn khai báo kiểu và tên biến, sau đó sử dụng toán tử gán (=) để đặt giá trị cho nó.
#include <stdio.h>
int main() {
int soNguyen; // Khai báo biến soNguyen kiểu int
double soThuc; // Khai báo biến soThuc kiểu double
soNguyen = 123; // Gán giá trị 123 cho soNguyen
soThuc = 45.678; // Gán giá trị 45.678 cho soThuc
printf("So nguyen: %d\n", soNguyen);
printf("So thuc: %.3f\n", soThuc); // .3f để in 3 chữ số thập phân
return 0;
}
b) Khai báo và khởi tạo giá trị ngay lập tức
Bạn có thể gán giá trị ban đầu cho biến ngay tại thời điểm khai báo.
#include <stdio.h>
int main() {
int tuoiHocSinh = 16; // Khai báo và khởi tạo tuoiHocSinh
float diemTrungBinh = 8.75f; // Khai báo và khởi tạo diemTrungBinh (chú ý 'f' cho float)
printf("Tuoi cua hoc sinh: %d\n", tuoiHocSinh);
printf("Diem trung binh: %.2f\n", diemTrungBinh);
return 0;
}
5. Phạm Vi (Scope) Của Biến
Phạm vi của một biến xác định phần nào của chương trình có thể truy cập được biến đó. C có ba loại phạm vi chính:
- Phạm vi khối (Block Scope): Biến được khai báo bên trong một khối mã (một cặp dấu ngoặc nhọn
{}) chỉ có thể được sử dụng trong khối đó và các khối con của nó. - Phạm vi hàm (Function Scope): Biến được khai báo bên trong một hàm chỉ có thể được sử dụng trong hàm đó. Các biến này còn được gọi là biến cục bộ (local variables).
- Phạm vi toàn cục (Global Scope): Biến được khai báo bên ngoài tất cả các hàm và khối mã (thường là ở đầu tệp nguồn) có thể được truy cập từ bất kỳ đâu trong chương trình. Các biến này được gọi là biến toàn cục (global variables).
6. Hằng Số
Hằng số là các giá trị cố định, không thay đổi trong suốt quá trình thực thi chương trình. Cung cấp hai cách chính để định nghĩa hằng số:
a) Sử dụng chỉ thị tiền xử lý #define
Chỉ thị này được xử lý trước khi biên dịch, thay thế mọi lần xuất hiện của tên hằng bằng giá trị của nó.
b) Sử dụng từ khóa const
Từ khóa const được dùng để khai báo một biến có giá trị không thể thay đổi sau khi khởi tạo.
#include <stdio.h>
// Định nghĩa hằng số PI bằng #define
#define GIA_TRI_PI 3.14159
// Định nghĩa hằng số tối đa bằng const
const int SO_LUONG_TOI_DA = 100;
// Hàm tính chu vi hình tròn
double tinhChuViHinhTron(double banKinh) {
double chuVi = 2 * GIA_TRI_PI * banKinh;
return chuVi;
}
int main() {
double banKinhHienTai = 10.0;
double ketQuaChuVi = tinhChuViHinhTron(banKinhHienTai);
printf("Chu vi hinh tron voi ban kinh %.2f la: %.2f\n", banKinhHienTai, ketQuaChuVi);
printf("So luong san pham toi da: %d\n", SO_LUONG_TOI_DA);
// SO_LUONG_TOI_DA = 120; // Dòng này sẽ gây lỗi biên dịch vì SO_LUONG_TOI_DA là hằng số
return 0;
}