1. Biên dịch và Liên kết Chương trình
- Xử lý tiền xử lý: mở rộng tệp tiêu đề, thay thế văn bản, loại bỏ chú thích, biên dịch điều kiện.
- Tập hợp: phân tích cú pháp + tổng hợp ký hiệu.
- Biên dịch: chuyển đổi mã nguồn thành lệnh nhị phân.
- Liên kết: kết hợp các tệp: giải quyết ký hiệu, điều chỉnh địa chỉ, tạo bảng ký hiệu.
2. Định nghĩa Macro bằng #define
- Macro: thay thế văn bản.
- Nhược điểm: a) Không kiểm tra kiểu, khó gỡ lỗi. b) Có thể bị ảnh hưởng bởi ưu tiên phép tính. c) Dễ dẫn đến lặp mã, làm tăng kích thước mã.
- Lợi ích: a) Không có chi phí khung ngăn xếp hàm (nhanh hơn).
Định nghĩa hằng số
#define PI 3.14159
#define MAX_VALUE 100
Định nghĩa hàm
#define SQUARE(x) ((x) * (x))
Thay thế đoạn mã
#define DEBUG_PRINT(x) printf("DEBUG: " #x " = %d\n", x)
3. Biên dịch Điều kiện
- Làm việc của bộ xử lý tiền xử lý, cho phép lựa chọn bao gồm hoặc loại trừ một phần mã dựa trên điều kiện tại thời điểm biên dịch.
- Các loại:
#if,#ifdef,#ifndef,#elif, và#else.
#if
#if BIỂU_THỨC_ĐIỀU_KIỆN
// Khối mã
#endif
#ifdef
#ifdef TÊN_MACRO
// Khối mã
#endif
#ifndef
#ifndef TÊN_MACRO
// Khối mã
#endif
#elif
#if BIỂU_THỨC_ĐIỀU_KIỆN_1
// Khối mã 1
#elif BIỂU_THỨC_ĐIỀU_KIỆN_2
// Khối mã 2
#else
// Khối mã 3
#endif
#else
#if BIỂU_THỨC_ĐIỀU_KIỆN
// Khối mã 1
#else
// Khối mã 2
#endif
Ngăn chặn việc bao gồm nhiều lần cùng một tệp tiêu đề
Sử dụng chỉ thị tiền xử lý #pragma once
#ifndef TEN_TEP_TIEU_DE_H
#define TEN_TEP_TIEU_DE_H
// Nội dung của tệp tiêu đề
#endif
4. Sự khác biệt giữa dấu ngoặc kép "" và dấu ngoặc nhọn <> khi bao gồm tệp tiêu đề
- Dấu ngoặc kép: tìm kiếm trước trong thư mục chứa tệp nguồn, sau đó tìm trong đường dẫn chuẩn nếu không tìm thấy.
- Dấu ngoặc nhọn: tìm trực tiếp trong đường dẫn chuẩn.
5. Mã Nguyên, Mã Đảo và Mã Bù
- Mã nguyên, mã đảo và mã bù của số dương giống nhau.
- Mã đảo của số âm được lấy bằng cách đảo ngược mã nguyên, mã bù được lấy bằng cách cộng 1 vào mã đảo, cộng 1 vào mã bù sẽ lại được mã nguyên.
- Số nguyên trong C được lưu dưới dạng mã bù trong bộ nhớ.
| Giá trị | Mã Nguyên | Mã Đảo | Mã Bù |
|---|---|---|---|
| +0 | 00000000 | 00000000 | 00000000 |
| -0 | 10000000 | 11111111 | 00000000 |
| +3 | 00000011 | 00000011 | 00000011 |
| -3 | 10000011 | 11111100 | 11111101 |
6. Thuật toán Byte Order (Ký tự Kết thúc)
- Kiểu byte order: cách dữ liệu được lưu trữ trong bộ nhớ.
- Kiểu Big-endian: byte thấp được lưu ở địa chỉ cao.
- Kiểu Little-endian: byte thấp được lưu ở địa chỉ thấp.
Ví dụ: 0x12345678 --Big-endian: 0x12 0x34 0x56 0x78 -- Little-endian: 0x78 0x56 0x34 0x12
Phương pháp xác định Big-endian hay Little-endian:
Sử dụng con trỏ
int kiemtra_hethong()
{
int gia_tri = 1;
return *(char*)(&gia_tri); // 1 : Little-endian 0 : Big-endian
}
Sử dụng union
int kiemtra_hethong()
{
union kiemtra
{
int gia_tri;
char mang[4];
};
union kiemtra du_lieu;
du_lieu.gia_tri = 1;
return du_lieu.mang[0];
}
7. Lưu trữ Số thực trong Bộ nhớ
| Bit Ký hiệu | Bit Chỉ số | Bit Phân số |
|---------------|-------------------|---------------------------|
| s | e | f |
- Bit Ký hiệu (s): 1 bit, 0 cho số dương, 1 cho số âm.
- Bit Chỉ số (e): 8 bit, biểu diễn phần chỉ số của số thực.
- Bit Phân số (f): 23 bit, biểu diễn phần phân số của số thực.
8. Kiểu Dữ liệu struct
struct Nguoi {
char gioi_tinh;
char ten[15];
int tuoi;
};
Đối齐 bộ nhớ
- Lý do về nền tảng: không phải tất cả các nền tảng phần cứng đều có thể truy cập dữ liệu ở bất kỳ địa chỉ nào.
- Lý do về hiệu suất: để đọc dữ liệu một cách hiệu quả nhất.
Các quy tắc đối齐 bộ nhớ trong struct
- Thành viên đầu tiên bắt đầu từ địa chỉ 0.
- Các thành viên khác được căn chỉnh đến bội số của kích thước tối đa.
- Kích thước tổng cộng của struct là bội số của kích thước tối đa.
9. Kiểu Dữ liệu union
union ten_union {
kieu_thanh_vien1 thanh_vien1;
kieu_thanh_vien2 thanh_vien2;
// có thể có thêm thành viên
};
10. Kiểu Dữ liệu enum
enum ThuTrongTuan {
ThuHai, //0
ThuBa, //1
ThuTu, //2
ThuNam, //3
ThuSau, //4
ThuBay, //5
ChuNhat //6
};
11. Con trỏ
- Con trỏ là biến lưu trữ địa chỉ, thông qua con trỏ có thể truy cập trực tiếp dữ liệu tại vị trí đó.
- Kiểu của con trỏ xác định số byte mà phép giải tham chiếu có thể truy cập.
Các loại con trỏ
char *chi_so = "xin chào thế giới";
int (*chi_so_mang)[10];
int* mang_chi_so[10];
void (*chi_so_ham)();
int (*mang_chi_so_ham[10])();
int (*(*chi_so_mang_chi_so_ham)[10])();
Mảng và Con trỏ
Truyền tham số
Mảng một chiều
void kiemtra(int mang[]) {}
void kiemtra(int mang[10]) {}
void kiemtra(int *mang) {}
void kiemtra2(int *mang[20]) {}
void kiemtra2(int **mang) {}
int main()
{
int mang[10] = {0};
int *mang2[20] = {0};
kiemtra(mang);
kiemtra2(mang2);
}
Mảng hai chiều
void kiemtra(int mang[3][5]) {}
void kiemtra(int mang[][5]) {}
void kiemtra(int (*mang)[5]) {}
int main()
{
int mang[3][5] = {0};
kiemtra(mang);
}
&tên mảng và tên mảng
- tên mảng: địa chỉ của phần tử đầu tiên.
- &tên mảng: địa chỉ của toàn bộ mảng.
12. Cấp phát Bộ nhớ động
malloc: cấp phát một khối bộ nhớ có kích thước đã chỉ định và trả về con trỏ đến khối bộ nhớ đó.calloc: tương tự như malloc, nhưng khởi tạo bộ nhớ bằng 0.realloc: thay đổi kích thước của một khối bộ nhớ đã cấp phát.free: giải phóng bộ nhớ đã cấp phát.
malloc
void* malloc(size_t kich_thuoc);
calloc
void* calloc(size_t so_phan_tu, size_t kich_thuoc);
realloc
void* realloc(void* chi_so, size_t kich_thuoc);
free
void free(void* chi_so);