CON TRỎ (nâng cao)

Con trỏ chưa bao giờ là dễ dàng với người học, vì sự trừu tượng của nó, và vì có nhiều khái niệm liên quan đến bộ nhớ, địa chỉ… vốn xa lạ với người mới. Lời khuyên trước tiên là bạn hãy đọc qua bài này: https://daohainam.com/2021/08/13/cau-chuyen-ve-con-tro-pointer/

Sau khi đọc xong, ta sẽ điểm thêm vài điều có thể bạn chưa biết:

👉 Trong ngôn ngữ máy không có khái niệm con trỏ:

Đúng vậy, con trỏ là một khái niệm của ngôn ngữ bậc cao. Trong ngôn ngữ máy hoặc assembly, bạn chỉ có khái niệm địa chỉ, vì đối với nó, địa chỉ cũng chỉ là một số nguyên nên chẳng có lý do gì lại phải có thêm một kiểu dữ liệu mới.Trong các ngôn ngữ bậc cao, người ta cần con trỏ để giúp xác định “kiểu của vùng nhớ mà con trỏ trỏ đến”.

Continue reading “CON TRỎ (nâng cao)”

HÀM main TRẢ VỀ GÌ?

int main(int argc, char *argv[])

int main (void)

public static void main(String [] args)

static void Main(string[] args)

def main():

Có lẽ bạn không lạ gì hàm main, hàm đầu tiên bạn viết khi học lập trình C, ngay cả khi chuyển sang một ngôn ngữ khác, nhất là các ngôn ngữ thừa kế từ C như C++, Java và C#, bạn cũng sẽ thấy một hàm tương tự. Đặc trưng của main là nó sẽ nhận vào các tham số (các tham số này được truyền cho chương trình đang chạy từ trên dòng lệnh) và trả về dữ liệu kiểu int hoặc void.

👉 Khi gọi một hàm (sqrt, rand, malloc…), bạn sẽ nhận được kết quả trả về của hàm đó, vậy giá trị trả về của hàm main sẽ trả về cho ai? Và để làm gì?👉 Vì khi main kết thúc cũng đồng nghĩa với chương trình kết thúc, nên bên trong chương trình bạn không có cách nào lấy giá trị đó (trừ khi bạn cố ý gọi main), mà giá trị này sẽ trả về cho hệ điều hành, hệ điều hành sẽ lưu lại và cho phép chương trình kế tiếp thực thi có thể đọc được. Nhờ khả năng chuyển kết quả thực thi của một chương trình cho một chương trình khác mà ta có thể viết được các chuỗi lệnh (hay các batch scripts, bash scripts…).

Continue reading “HÀM main TRẢ VỀ GÌ?”

64 bit? 32 bit?

Mỗi khi cài đặt Windows, Linux, các phần mềm, ta lại nghe đến khái niệm 32bit hoặc 64bit, vậy chúng là gì? Ta cùng tìm hiểu xem nhé.

👉 Bộ nhớ máy tính:Bộ nhớ máy tính là một dãy byte liên tiếp được sắp xếp từ vị trí 0, sau đó tăng dần, byte kế tiếp nằm ở vị trí 1, rồi 2, 3, 4…, mỗi byte có thể được truy xuất thông qua vị trí, hay còn gọi là địa chỉ. Như vậy byte đầu tiên sẽ có địa chỉ 0, byte thứ 1000 có địa chỉ 999. Để truy xuất vào 1 byte nào đó ta cần biết địa chỉ của nó.

👉 Thanh ghi trong máy tính:Thanh ghi là các vùng bộ nhớ nhỏ trong CPU, được dùng lưu trữ dữ liệu để làm việc, ta có thể coi nó giống như các tờ giấy note nhỏ CPU sử dụng trong lúc làm việc. Có nhiều thanh ghi khác nhau, mỗi thanh sẽ có tên và nhiệm vụ riêng, một số thanh ghi bạn có thể dùng lưu trữ chung như AL, AH, AX, EAX, EBX, ECX… một số khác được sử dụng cho một mục đích cụ thể: IP lưu địa chỉ lệnh kế tiếp sẽ được thực hiện, SP chỉ đến stack, CS, DS, ES… chỉ đến các phân đoạn (segment) bộ nhớ… Các thanh ghi có đuôi L (low) và H (high) là các thanh ghi 8 bit, vốn là 2 nửa của các thanh ghi đuôi X, AL và AH chính là 2 phần của AX, tương tự cho BX, CX… Vì là hai nửa cao và thấp nên thay đổi giá trị của AL hoặc AH cũng làm thay đổi AX. Tưởng tượng AL có giá trị là 0x20, AH là 0xFF, thì AX sẽ có giá trị là 0xFF20.

Các thanh ghi AX, BX,CX, DX, IP, SP… là các thanh ghi 16 bit, tức giá trị tối đa nó có thể chứa là 65535.

Continue reading “64 bit? 32 bit?”

THAM CHIẾU VÀ THAM TRỊ

Một trong những vấn đề các bạn mới học C/C++ hay gặp lỗi là truyền tham số khi gọi hàm, trong bài này mình sẽ giải thích kỹ để các bạn có thể hiểu rõ.

Trước khi bắt đầu các bạn nên đọc qua 2 bài viết về con trỏbộ nhớ stack.

Như đã biết, khi gọi hàm, tham số sẽ được tạo ra trên stack và được giải phóng NGAY KHI kết thúc. Có nghĩa là các giá trị của nó sẽ bị hủy. Giả sử bạn có một hàm được khai báo là void f(int n), khi bạn gọi f(m), trước khi thực thi, tham số n sẽ được tạo ra trên stack, giá trị của m sẽ được sao chép vào n. Bên trong f sẽ không có bất kỳ liên hệ nào với m, nên khi kết thúc hàm trở về, ta sẽ thấy m vẫn còn mang giá trị cũ, vì những gì thay đổi trên n là thay đổi biến n trong stack.Trong C chỉ có 1 cách truyền đó nên khi muốn giữ lại giá trị của tham số, ta phải quy ước là truyền con trỏ cho hàm, và bên trong hàm đó bạn sẽ thao tác trên vùng nhớ mà con trỏ đó trỏ đến.Như vậy khi ta khai báo fx(int *n), rồi gọi fx(&m) thì một biến con trỏ sẽ được tạo ra trên stack, giá trị của nó sẽ được sao chép từ địa chỉ của m. Bên trong fx, khi nói đến n nghĩa là đang nói đến địa chỉ của m, do vậy *n chính là biến m, thay đổi giá trị của *n cũng chính là thay đổi m.Trong C chỉ có một cách duy nhất là truyền theo tham trị, truyền theo con trỏ cũng chỉ là truyền theo tham trị, chỉ khác là bạn dùng biến có kiểu con trỏ mà thôi, bên trong hàm bạn vẫn phải xử lý biến đó theo cách sử dụng con trỏ.Hãy đảm bảo bạn đã hiểu toàn bộ phần trên trước khi đọc phần tiếp theo, vì phần trên mới là phần quan trọng nhất.

Continue reading “THAM CHIẾU VÀ THAM TRỊ”

VỀ ĐỊA CHỈ 0

Địa chỉ 0 vốn là một địa chỉ hoàn toàn hợp lệ, tuy nhiên con trỏ có địa chỉ bằng 0 (hay NULL) trong hầu hết các trường hợp là không hợp lệ, tức nếu truy cập vào vùng nhớ thông qua con trỏ có địa chỉ NULL sẽ gây ra lỗi. Nguyên nhân là vì bạn chỉ có thể truy cập vào những vùng nhớ đã-được-cấp-phát, mà vùng 0 thì vốn luôn được sử dụng bởi hệ thống và sẽ không bao giờ sẵn dùng (available) cho ứng dụng của bạn.

❗️Tất cả các vùng nhớ khác cũng vậy chứ không chỉ riêng địa chỉ 0, bạn chỉ có thể đọc ghi vào cùng nhớ được cấp cho việc chứa dữ liệu – ngay cả vùng nhớ đã được cấp cho việc chứa code bạn cũng không được đọc nữa.

– Trong các ngôn ngữ C/C++, NULL chỉ là 1 macro thay thế cho 0.

– Trong Pascal người ta dùng từ khóa nil thay cho NULL.

– Trong Java ta có NullPointerException, .NET có NullReferenceException sẽ throw nếu bạn truy cập vào một biến == null.

BỘ NHỚ STACK LÀ GÌ? TẠI SAO LẠI CÓ LỖI STACK OVERFLOW?

Hiểu về Stack để tránh Stack Overflow!Các bạn mới lập trình chắc hay thấy lỗi này, đặc biệt là khi học đến phần đệ quy, vậy bản chất của nó là gì?

☠️☠️☠️ Lưu ý: bài này chỉ dành cho ai muốn hiểu sâu về kỹ thuật – không chỉ định với người thích ăn xổi ☠️☠️☠️

Mỗi chương trình khi được tải vào máy tính để thực thi sẽ được cung cấp một phần bộ nhớ, phần bộ nhớ này sẽ được chia ra làm nhiều loại, với mục đích khác nhau. Một phần sẽ được dùng để chứa mã lệnh, thường thì phần này sẽ chỉ để đọc và chạy các lệnh chứa trong đó, một phần khác lại được dùng để chứa dữ liệu, bạn có thể đọc và ghi thoải mái, nhưng phải xin cấp phát trước khi dùng (malloc, new…) để tránh ghi đè lên dữ liệu của ứng dụng khác (ta hay gọi là bộ nhớ Heap).

Đọc thêm bài con trỏ để hiểu hơn về bộ nhớ máy tính: https://www.facebook.com/namdotnet/posts/1283909971794016

🧨 Còn một phần đặc biệt nữa gọi là bộ nhớ Stack 🧨

Continue reading “BỘ NHỚ STACK LÀ GÌ? TẠI SAO LẠI CÓ LỖI STACK OVERFLOW?”

CÂU CHUYỆN VỀ CON TRỎ (POINTER)

Con trỏ là một khái niệm sử dụng rất nhiều khi học về cấu trúc dữ liệu và giải thuật, phần cây hoặc danh sách liên kết. Ở đây mình sẽ nói sâu vào khái niệm này.(lưu ý đây là bài viết sâu về kỹ thuật nên nếu không hiểu thì hỏi chứ không được phàn nàn sao nó quá khó hiểu nhé 😐)

Continue reading “CÂU CHUYỆN VỀ CON TRỎ (POINTER)”