Tải bản đầy đủ (.doc) (17 trang)

báo cáo Sơ lược về bộ nhớ màn hình-Danh sách liên kết

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (281.87 KB, 17 trang )

Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Nhận xét của GVHD
















































Bài tập lớn môn Cơ sở lập trình 2 Page 1
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Mục lục
Trang
Lời giới thiệu 3
Chương 1: Vấn đề bộ nhớ màn hình trong textmode 4
Sơ lược về Video RAM, các dạng địa chỉ 4
Cách truy cập trực tiếp bộ nhớ 6
Cấu trúc bộ nhớ màn hình ở textmode 10
Cách tính địa chỉ của một ví trí (x, y ) trên màn hình 12
Cách cắt và lưu một vùng hay toàn bộ màn hình 12
Chương 2: Danh sách liên kết đơn – đôi và ứng dụng 12

Khái niệm và mô tả 12
Các đặc trưng, ưu khuyết điểm khi thao tác 13
Cài đặt cụ thể trong C, với thuộc tính Info có kiểu là chuỗi 14
Nêu các lĩnh vực ứng dụng 15
Tài liệu tham khảo 16
Bảng phân công công việc cụ thể 16
Bài tập lớn môn Cơ sở lập trình 2 Page 2
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Lời nói đầu
Trong hầu hết các chương trình ứng dụng hiện nay, các chức năng thường
được hiển thị dưới dạng một MENU tạo thuận lợi cho người sử dụng.
Nhóm 07 chúng tôi tham gia nghiên cứu đề tài 07 về bộ nhớ màn hình và
danh sách liên kết nhằm tạo ra một MENU như trình soạn thảo C.
Trong quá trình tham gia nghiên cứu đề tài này, nhóm 07 chúng tôi đã nhận
được sự giúp đỡ tận tình của tất cả các bạn trong lớp, và đặc biệt là sự giúp đỡ của
thầy CVHT Nguyễn Trần Thi Văn.
Tuy nhiên chúng tôi không thể tránh khỏi những sai sót. Rất mong những ý
kiến đóng góp nhiệt tình của tất cả các bạn.
Nhóm 07
Bài tập lớn môn Cơ sở lập trình 2 Page 3
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Chương 1: Vấn đề bộ nhớ màn hình trong textmode
1.1 Sơ lược về Video RAM, các dạng địa chỉ (segment, offset, v.v…)
1.1.1 Sơ lược về Video RAM:
Thuật ngữ Video RAM (VRAM) được dùng để chỉ tất cả các loại bộ nhớ truy xuất
ngẫu nhiên (RAM), để lưu dữ liệu hình ảnh cho màn hình hiển thị của máy tính. Tất cả
các loại VRAM đều được cải biến đặc biệt từ RAM động (DRAM).
Theo truyền thống, chuẩn DRAM thường sử dụng cho video cards thì không đủ
băng thông để sử dụng card màn hình ở độ phân giải cao với tốc độ làm tươi có thể chấp
nhận được. Khi truy xuất thông tin vào video memory thì máy tính phải thực hiện hai

thao tác: bộ xử lý thì ghi thông tin mới vào bộ nhớ, và RAMDAC đọc nó nhiều lần trên
một giây để mà gởi tín hiệu video đến màn hình.
Để khắc phục hạn chế này, một loại bộ nhớ mới đã được tạo ra là video RAM
(VRAM). Giống như tên của nó, bộ nhớ này đặc biệt thích hợp cho việc sử dụng video
systems. VRAM thật sự là vùng nhớ đệm (buffer) giữa bộ vi xử lý máy tính và hệ thống
hiển thị (display), và thường được gọi là frame buffer (bộ nhớ đệm khung hình). Khi
chuẩn bị được gởi tới màn hình, các hình ảnh trước tiên sẽ được CPU đọc như là dữ liệu
từ 1 dạng bộ nhớ chính nào đó rồi mới được ghi vào VRAM. Từ VRAM, các dữ liệu
hình ảnh đó được RAMDAC (một công cụ chuyển đổi từ digital sang analog dùng RAM)
chuyển đổi thành các tín hiệu analog để gởi đến cơ cấu hiển thị như các bóng đèn hình
CRT hay LCD. Thông thường, VRAM được đóng gói dưới dạng các con chip rời và
nằm ngay trên card tăng tốc đồ họa. Hầu hết các loại VRAM đều có 2 cổng: trong khi
CPU đang ghi 1 hình ảnh mới vào VRAM, thì màn hình đọc dữ liệu từ VRAM để làm
mới nội dung hiển thị của mình. Khác nhau cơ bản giữa VRAM và chuẩn DRAM đó là
VRAM là một cổng đôi dual-ported. Điều này có nghĩa là nó có hai con đường truy xuất,
và có thể được ghi và đọc một cách đồng thời. Thuận lợi của điều này là nó làm cho tốc
độ xử lý của video card rất lớn: nhiều lần trên một giây những hình ảnh trên màn hình
được xử lý và được ghi vào bộ nhớ, đồng thời nhiều lần trên giây bộ nhớ này đọc và gởi
nó đến màn hình. Cổng đôi thì cho phép những thao tác này thực hiện.
Note: Đừng nhầm lẫn thuật ngữ "video RAM" với “video memory”.
Khác với memory trong hệ thống và do nhu cầu về đồ hoạ ngày càng cao, các
hãng chế tạo graphic card đã chế tạo VRAM riêng cho video card của họ mà không cần
dùng memory của hệ thống chính. VRAM chạy nhanh hơn vì ứng dụng công nghệ Dual
Port nhưng đồng thời giá thành cũng đắt hơn rất nhiều.
Đối với các máy họ IBM dải ô nhớ từ A0000h đến BFFFFh của bộ nhớ 1MB
được dành cho RAM Video. Nhưng không phải toàn bộ các ô nhớ này luôn được sử
dụng, nó còn phụ thuộc vào chế độ làm việc văn bản hay đồ họa và độ phân giải của thẻ
Video.
Bài tập lớn môn Cơ sở lập trình 2 Page 4
Sơ lược về bộ nhớ màn hình-Danh sách liên kết

Ví dụ: Ở chế độ làm việc văn bản có màu của VGA (Video Graphics Array) thì
địa chỉ làm việc với màn hình bắt đầu từ địa chỉ B80000h.
Trong chế độ văn bản (textmode ) các ký tự được truy cập theo từng ma trận
điểm ảnh.
Hình ảnh ma trận gồm một lưới hình chữ nhật các điểm (ví dụ 640*480). Độ phân giải
(số điểm ảnh trong màn hình) thường cho dưới dạng h*v, trong đó h là số lượng pixcel
theo dòng và v là số lượng pixcel theo cột.
Độ phân giải = số điểm ngang*số điểm dọc*số màu (số bit màu)
Ví dụ: 800*600*16 bits=960 000 bytes 1Mb
1024*768*32 bits=3 145 728 bytes 4Mb
Ma trận điểm ảnh này được bố trí theo chiều ngang và chiều đứng và tạo thành
một hộp ký tự. Mỗi hộp ký tự chỉ dùng để hiển thị một ký tự và kích thước ma trận của
hộp ký tự phụ thuộc vào từng loại thẻ video.
IBM PC hỗ trợ 3 loại màn hình cơ cản có tên tùy thuộc vào loại Card màn hình cắm
trên Bus mở rộng trên Mainboard như: Monochrome cho hiển thị text đơn sắc; CGA
(Color Graphic Adaptor) cho phép hiển thị text và đồ họa; EGA (Enhanced Graphics
Adaptor) hiển thị text và đồ họa với độ phân giải cao hơn. Ngoài ra còn có card VGA
(Video Graphics Array), SVGA
1.1.2 Các dạng địa chỉ:
1.1.2.1 Segment:
Segment (Đoạn): Một đoạn bộ nhớ là một khối gồm 2
16
ô nhớ liên kết nhau. Mỗi
đoạn được đánh dấu bằng địa đoạn,địa chỉ đoạn đầu tiên là 0, địa chỉ đoạn lớn nhất là
F000h. Bên trong mỗi đoạn của ô nhớ được xác định bằng một địa chỉ tương đối là
Offset. Như vậy trong mỗi đoạn bytes đầu tiên có Offset là 0, bytes cuối cùng có Offset là
FFFFh.
Số lượng các ngăn nhỏ mà bộ xử lý có thể truy nhập được phụ thuộc trực tiếp
vào kích thước của một thanh ghi đặc biệt-thanh ghi địa chỉ. Mỗi ngăn nhỏ chỉ có thể
được gọi thông qua một giá trị tương ứng được đặt trong thanh ghi địa chỉ do vậy thanh

ghi quyết định số lượng ngăn nhỏ của bộ nhớ. Đối với các bộ vi xử lý trước 8088 thanh
ghi địa chỉ la 16 bit. Nó chỉ có thể nhận được các giá trị trong khoảng từ 0 đến 65535và
do vậy không thể địa chỉ hoá bộ nhớ lớn hơn 65536 ngăn (ngăn nhỏ 0 cũng phải được
tính). Nếu chúng ta muốn truy cập hơn 1 triệu ngăn nhỏ thì phải có thanh ghi địa chỉ
kích thướt lớn hơn 16 bit. Cần phải có 20 bit để đạt được 1 vùng địa chỉ là 1 Mb (2
20
byte=1024 Kb=1Mb). Cách giải quyết có vẻ không đến nỗi là phức tạp về nguyên tắc chỉ
cần thêm 1 thanh ghi địa chỉ chỉ 20 bit.
Giải pháp tối ưu này về nguyên tắc là 8088 không có thêm một thanh ghi địa chỉ
đặc biệt nào mỗi khi truy cập bộ nhớ nó sẽ tạo địa chỉ trên cơ sở của hai thanh ghi 16 bit
bình thường hai thanh ghi này tổ hợp với nhau để tạo thành một số 20 bit hoặc lớn hơn.
1.1.2.2 Offset:
Một trong hai thanh ghi nào luôn luôn được tạo thành từ một trong bốn
thanh ghi mảng (DS, ES, CS, SS). Đó chính là địa chỉ Segment của mảng nhớ. Một đoạn
nhớ (Segment ) là một khối gồm 2
16
byte liên tiếp nhau. Mỗi đoạn được đánh dấu bằng
địa chỉ đoạn bắt đầu là 0, đia chỉ lớn nhất là FFFFh. MP 8088 lấy số thứ hai từ một
thanh ghi khác hoặc từ một ngăn nhỏ và đó là địa chỉ Offset của mảng nhớ. Tuy nhiên,
hai giá trị này không phải được cộng với nhau 1 cách bình thường vì theo cách này ta
Bài tập lớn môn Cơ sở lập trình 2 Page 5
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
chỉ nhận được một số 17 bit và lớn nhất sự tổ hợp này phức tạp hơn nhiều. Địa chỉ
Offset cung cấp cho ta vị trí chính xác của ngăn nhớ trong một mảng. Bởi lẻ thanh ghi
Offset không thể có kích thước lớn hơn 16 bit, nên một đoạn có kích thước 2
16
bytes có
nghĩa là 64 Kb.
Địa chỉ được tính từ tổ hợp của hai đia chỉ mảng và Offset được gọi là địa chỉ
vật lý. Nó chỉ ra địa chỉ tuyệt đối của ngăn nhớ còn bản thân địa chỉ mảng và địa chỉ

Offset được gọi là địa chỉ logic.

Để xác định một địa chỉ vật lý trong 1 Mb bộ nhớ (20 bit), người ta dùng hai địa chỉ là
địa chỉ đoạn và địa chỉ Offset trong đoạn kết hợp lại với nhau:
Đoạn: offset trong đoạn (segment: offset)
Khi lập trình người ta chỉ cần sử dụng địa chỉ vật lý cụ thể trong bộ nhớ do CPU tự đổi:
Ví dụ: 3456:0C3D Đoạn 3456h Offset 0C3Dh
Cách chuyển đổi địa chỉ logic sang địa chỉ vật lý
Để chuyển đổi một địa chỉ logic sang địa chỉ vật lý người ta dịch trái địa chỉ segment 4
bit (tương đương với việc nhân cho 16 hay 10h) rồi cộng với đia chỉ offset
Ví dụ:
4B3C: 1234 (địa chỉ logic) (địa chỉ vật lý)
4B3C
+ 12 34
4C5F4 (địa chỉ vật lý)
1.1.2.3 Cách ghi địa chỉ bộ nhớ
Mỗi địa chỉ bộ nhớ máy tính PC trong chế độ thực bao gồm hai phần, thể hiện
bằng số nguyên không dấu, thường viết dưới dạng mã hệ 16. Hai phần viết cách nhau
một dấu hai chấm(:). Phần đứng trước dấu hai chấm gọi là phần địa đoạn (segment).
Phần đứng sau dấu hai chấm gọi là độ lệch (offset). Ví dụ:
0xB800:0x0000
Là địa chỉ đầu vùng nhớ màn hình văn bản, trong đó 0xB800 là địa chỉ segment,
và 0x0000 là địa chỉ offset.
Sở dĩ thể hiện phức tạp như vậy là vì bộ nhớ máy tính PC chuẩn ở chế độ thực có
thể đánh địa chỉ được tối đa là 1Mb. Để đánh địa chỉ được cho từng byte một phải cần
một số nguyên 20 bit. Nhưng các thanh ghi của CPU 80286 của Intel chỉ có độ dài 16 bit.
Vì vậy bắt buộc phải dùng 2 thanh ghi và tách địa chỉ bộ nhớ làm 2 phần để ghi lên hai
thanh ghi đó. Phần segment đánh số các ô nhớ có địa chỉ tuyệt đối là bội số của 16. Phần
offset ghi độ chuyển dịch của một ô nhớ so với một địa chỉ segment đã chọn.Từ hai giá
trị này có thể tính ra địa chỉ tuyệt đối của một ô nhớ như sau:

Địa chỉ tuyệt đối= Địa chỉ segment*16+Địa chỉ offset
Mỗi ô nhớ trong bộ nhớ có một địa chỉ tuyệt đối duy nhất, nhưng có thể được
viết dưới dạng nhiều cách khác nhau, tuỳ thuộc vào địa chỉ segment. Còn đối với cùng
địa chỉ segment thì việc đánh địa chỉ là nhất quán. Tất cả các ô nhớ được ghi điạ chỉ
offset căn cứ vào một địa chỉ segment tạo nên một vùng nhớ được gọi là một segment,
hay một đoạn. Tuy vậy nhưng với thanh ghi 16 bit, chỉ có thể mã hoá được tối 65536 địa
chỉ offset khác nhau. Không thể có độ dịch chuyển nào lớn hơn giá trị đó, hay nói cách
khác, dung lượng của một segment không thể vượt qua giá trị 65536 byte, hay 64 Kb.
Bài tập lớn môn Cơ sở lập trình 2 Page 6
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
1.2 Cách truy nhập trực tiếp bộ nhớ: các hàm peek (), poke (), MK_FP, FP_SEG,
FP_OFF, …
1.2.1 Tổ chức bộ nhớ của máy tính:
Bộ nhớ làm việc dưới hệ điều hành DOS đuợc chia làm 3 phần chính:

Hình 2: Sơ đồ bộ nhớ của máy tính PC.
1.2.1.1 Vùng nhớ quy ước:
Là vùng nhớ có dung lượng 640 Kb, bắt đầu từ địa chỉ tuyệt đối 0x00000 hay
địa chỉ 0x0000:0x0000 theo cách viết mà ta đã trình bày. Vùng này có thể chia thành hai
vùng chính:
Đoạn từ 0x0000:0x0000 đến 0x0000:0x06FF dùng để chứa các thông tin được
chương trình khởi động(BOOT) và hệ điều hành nạp lên trong quá trình khởi động,
trong đó có:
• Bảng vectơ ngắt chiếm 4K, từ 0x0000:0x0000 đến 0x0000:03FF
• Các thông tin chung của ROMBIOS, DOS và của các thiết bị chiếm 3K, từ
0x0000:0x0400 đến 0x0000:06FF.
Bài tập lớn môn Cơ sở lập trình 2 Page 7
XXXXX Tuỳ theo kích thước bộ nhớ và
bộ vi xử lý
EMB

Bộ nhớ HMA
Vùng nhớ
mở rộng
XMS
FFFF:FFFF
FFFF:0010
64 Kb Byte
FFFF:000F
FC00:0000
Phần thường trú của hệ điều
hành(DOS)
VÙNG ROM
BIOS 64 KB
Vùng nhớ cao(UMA hoặc TOP384)
Vùng nhớ địa chỉ hoá dướI 1 Mb
FBFF:000F
F000:0000
48 Kb dành riêng
EFFF:000F
C000:0000
192 Kb ROM mở rộng
Vùng bộ nhớ
phân trang
BFFF:000F
A000:0000
128 Kb Bộ nhớ các card điều
khiển 8 bit
9FFF:000F
0000:0000
Phần thường trú của DOS và

chương trình người dùng
Vùng nhớ quy ước 640 Kb
0000:06FF
0000:0500
Thông tin chung
của ROM-BIOS
và DOS về các
thiết bị
0000:04FF
0000:0400
Thông tin của
ROM-BIOS
0000:03FF
0000:0000
Các vectơ ngắt
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Từ địa chỉ 0x0000:0x0700 đến 0x9FFF:0x000F chứa phần thường trú của
COMMAND.COM và các trình thường trú khác ( trình điều khiển chuột, trình cảnh
báo virus, bộ gõ tiếng Việt…); phần còn lại dành cho chương trình người dùng. Người
lạp trình có thể tung hoành trong vùng này một cách tương đối an toàn. Nhưng chỉ lỡ
xâm phạm vào vùng nhớ của các trình thường trú, hoặc làm sai lạc giá trị các vùng
trước đó thì sẽ thấy ngay các chuyện kỳ quặc hoặc treo máy. Dung lượng của vùng nhớ
quy ước là 9FFF
16
x 16
10
+000F
16
+ 1 = 655360
10

hay 640 Kb.
1.2.1.2 Vùng nhớ cao(UMA)
Là phần còn lại 384 Kb của 1Mb trừ đi 640 Kb. Là vùng nhớ của các card điều khiển
hay ánh xạ vùng nhớ trên các thiết bị, của ROM mở rộng, và của ROM-BIOS. Đặc biệt
trong vùng này có phần bộ nhớ của card màn hình hoặc để ánh xạ bộ nhớ màn hình, là
địa chỉ rất thú vị dành cho người lập trình. Phần nào còn bỏ ngỏ thì các phiên bản DOS
về sau thường gửi các trình thường trú của mình lên đó để dành thêm dung lượng làm
việc cho người dùng ở phần vùng nhớ quy ước.
1.2.1.3Vùng HMA
Khi dùng tới 20 bit để ghi địa chỉ thì thực tế số byte có thể đánh địa chỉ sẽ nhỉnh hơn
1 Mb một chút. Cụ thể như sau:
Băng này ghi được 2
20
– 2
4
=1048576 – 16 =1048560 byte
Thanh ghi đoạn.
(segment)
Băng này ghi được 2
16
= 65536 byte
Thanh ghi offset
Tổng cộng ghi được 1114096 byte =1048560 + 65536= 1 Mb + 64 Kb - 16 byte.
Hình 1 Cách sử dụng hai thanh ghi để đánh địa chỉ của máy tính PC.
Ta sẽ có thêm “thiếu 16 byte đầy 64 Kb”nữa. Vùng này gọi là vùng nhớ HMA.
1.2.2 Con trỏ gần và con trỏ xa:
Một chương trình khi được nạp vào bộ nhớ RAM để sẵn sàng chạy thường được tổ
chức như sau:
Phần mã trong một đoạn được gọi là đoạn mã, có địa chỉ đoạn đặt tại thanh ghi CS.
Phần dữ liệu tĩnh, các biến toàn cục được đặt trong một đoạn gọi là đoạn dữ liệu, có

địa chỉ đoạn đặt tại thanh ghi DS.
Phần dữ liệu tạm thời, dữ liệu cục bộ đặt trong đoạn ngăn xếp, có địa chỉ đoạn đặt
tại thanh ghi SS.
Một biến tĩnh hay biến toàn cục bất kỳ do đó có địa chỉ offset16 bit được tính căn cứ
vào địa chỉ đoạn ghi trong thanh ghi DS. Tổng dung lượng các biến này không vượt quá
64Kb.
Một con trỏ nếu có giá trị chỉ trong phạm vi 16 bit có nghĩa là nó trỏ vào một ô nhớ
thuộc đoạn dữ liệu, với địa chỉ đoạn ngầm hiểu là địa chỉ đoạn dữ liệu ghi trong DS. Con
trỏ này được gọi là con trỏ gần (near). Phần bộ nhớ còn dư, sau khi bố trí các biến tĩnh
và biến cục bộ trong đoạn dữ liệu được gọi là phần heap gần.
Cũng có thể khai thác các biến con trỏ gần với địa chỉ đoạn ngầm hiểu trong thanh
ghi CS, thanh ghi SS. Lúc đó, con trỏ cũng chỉ là 16 bit.
Ngoài phần bộ nhớ được tổ chức dành riêng cho chương trình như trên, phần bộ
nhớ tự do còn lại của RAM được gọi là vùng heap xa. Giá trị của một con trỏ trỏ tới
vùng này không còn có thể căn cứ vào địa chỉ đoạn trong các thanh ghi DS, CS, hay SS
được nữa, và do đó phải được mã hoá bằng 32bit, với 16 bit ghi địa chỉ đoạn, 16 bit ghi
địa chỉ offset. Con trỏ như vậy gọi là con trỏ xa(far).
Bài tập lớn môn Cơ sở lập trình 2 Page 8
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
1.2.3 Các hàm truy cập trực tiếp bộ nhớ:
1.2.3.1 Hàm poke( ), pokeb( ) <DOS.H>
Công dụng:
■ poke gửi giá trị nguyên vào bộ nhớ tại địa chỉ phân đoạn segment:offset
■ pokeb gửi giá trị kí tự value vào bộ nhớ tại địa chỉ phân đoạn
segment:offset
Khai báo (declaration):
■ void poke(unsigned segment, unsigned offset, int value);
■ void pokeb(unsigned segment, unsigned offset, char value);
Giá trị trả về: None
1.2.3.2 Hàm peek( ), peekb( ) <DOS.H>

Công dụng:
■ peek nhận một số nguyên từ bộ nhớ tại địa chỉ phân đoạn segment:offset
■ peekb nhận một kí tự từ bộ nhớ tại địa chỉ phân đoạn segment:offset
Khai báo (declaration):
■ int peek(unsigned segment, unsigned offset);
■ char peekb(unsigned segment, unsigned offset);
Giá trị trả về:
■ peek trả về dữ liệu kiểu word tại địa chỉ phân đoạn segment:offset
■ peekb trả về dữ liệu kiểu word tại địa chỉ phân đoạn segment:offset

1.2.3.3 Hàm movedata ( ): <MEM.H, STRING.H>
Công dụng: Sao n byte từ địa chỉ nguồn (srcseg:srcoff) đến địa chỉ đích
Khai báo (declaration):
■void movedata(unsigned srcseg, unsigned srcoff,unsigned destseg,
unsigned destoff, size_t n);
Giá trị trả về: None
1.2.3.4 Hàm FP_OFF ( ),FP_SEG( ), MK_FP( )
Công dụng:
■ FP_OFF là một macro nhận hoặc đặt địa chỉ offset
■ FP_SEG là một macro nhận hoặc đặt địa chỉ segment
■ MK_FP tạo một con trỏ far

Khai báo:
■ unsigned FP_OFF(void far *p);
■ unsigned FP_SEG(void far *p);
■ void far *MK_FP(unsigned seg, unsigned ofs);

Giá trị trả về:
■ FP_OFF trả về giá trị số nguyên đại diện cho giá trị của offset.
■ FP_SEG trả về giá trị số nguyên đại diện cho giá trị của segment.

■ MK_FP trả về một con trỏ.
1.2.4 Cách chuyển đổi địa chỉ:
Để chuyển từ địa chỉ thực sang địa chỉ phân đoạn ta dùng các macro sau:
unsigned FP_SEG(địa_chỉ_thực)
unsigned FP_OFF(địa_chỉ_thực)
Để chuyển ngược lại ta dùng các macro: void far *MK_FP(đoạn, độ_lệch)
Ví dụ sau khi thực hiện các câu lệnh:
Bài tập lớn môn Cơ sở lập trình 2 Page 9
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
char buf [100];
unsigned ds,dx;
ds= FP_SEG(buf);
dx= FP_OFF(buf);
thì ds:dx chứa địa chỉ của mảng buf.
Ngược lại, giả sử tại es: bx chứa địa chỉ của một vùng nhớ nào đó. Để thu được địa
chỉ thực của vùng nhớ này tại con trỏ pchar ta làm như sau:
Char *pchar;
Pchar=(char*)MK_FP(es,bx);
Ví dụ sau khi thực hiện các câu lệnh:
Char *pchar;
Pchar=(char*)MK_FP(0xb800:0);
Thì pchar trỏ tới địa chỉ đầu của bộ nhớ màn hình. Khi đó ta có thể sử dụng các lệnh
gán để truy cập trực tiếp tới bộ nhớ màn hình.

1.3 Cấu trúc bộ nhớ màn hình ở textmode: địa chỉ bắt đầu, kích thước, cách lưu trữ, giá
trị và ý nghĩa của byte thuộc tính,… )
1.3.1 Bộ nhớ màn hình (Display memory)
Bộ nhớ màn hình là vùng bộ nhớ dùng để chứa dữ liệu trực tiếp hiện ra màn
hình, dữ liệu trong bộ nhớ màn hình thay đổi sẽ trực tiếp thay đổi trên màn hình. Ở chế
độ văn bản (text mode ), bộ nhớ chủ dành cho bộ nhớ màn hình được bắt đầu từ địa chỉ

B800:0000. Ở chế độ đồ hoạ (graphics mode) bộ nhớ chủ dành cho bộ nhớ màn hình
được bắt đầu từ địa chỉ A000:0000. Với màn hình VGA kích thước chuẩn của bộ nhớ
màn hình là 256Kb.
1.3.2 Địa chỉ bắt đầu bộ nhớ màn hình:
Bộ nhớ màn hình bắt đầu từ địa chỉ: 0xB800:0x0000
Bài tập lớn môn Cơ sở lập trình 2 Page 10
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
1.3.3 Cách lưu trữ một kí tự trên màn hình:
Khi đưa một kí tự vào bộ nhớ màn hình, thì nó sẽ hiện lên màn hình. Mỗi kí tự
trên màn hình chiếm 2 byte trong bộ nhớ màn hình: byte đầu chứa mã ASCII, bye thứ
hai biểu diễn màu hiển thị gọi là byte thuộc tính.
1.3.4 Giá trị và ý nghĩa của byte thuộc tính:
Byte thuộc tính được mô tả như sau: Bit đầu tiên định nghĩa cờ chớp, 3 bit tiếp
theo định nghĩa màu nền, bit tiếp theo định nghĩa cờ sáng, 3 bit còn lại định nghĩa màu
chữ (màu kí tự ).
Ví dụ:
B7B6B5B4B3B2B1B0 được phân làm 3 nhóm:
Nhóm 1 gồm bit B7 biểu thị sự nhấp nháy,nếu B7 =0 thì kí tự không nhấp nháy, nếu B7
=1 thì kí tự sẽ nhấp nháy.
Nhóm 2 gồm bit B6B5B4 biểu thị 8 màu nền của kí tự.
Nhóm 3 gồm bit B3B2B1B0 biểu thị 16 màu kí tự.
Bảng màu:
Màu nền Màu chữ
FOREGROUND OR
BACKGROUND COLOR FOREGROUND COLOR ONLY
000 BLACK 1000 GRAY
001 BLUE 1001 LIGHT BLUE
010 GREEN 1010 LIGHT GREEN
011 CYAN 1011 LIGHT CYAN
100 RED 1100 LIGHT RED

101 MAGENTA 1101 LIGHT MAGENTA
110 BROWN 1110 YELLOW
111 WHITE 1111 BRIGHT WHITE
Ví dụ: 01101110: 06EH nền Brown, chữ Yellow, không nhấp nháy.
11010010: 0D2H nền Magenta, chữ Green, nhấp nháy.
1.3.5 Nguyên tắc tạo mầu của màn hình:
Mỗi pixel trên màn hình là sự pha trộn của 3 mầu cơ bản tương ứng với 3 ống tia
điện tử. Từ 3 mầu này ta có thể tạo được hầu hết các mầu có trong tự nhiên.
Chẳng hạn để có 16 màu từ 3 màu cơ bản trên người ta sử dụng 4 bit, 3 bit ứng với 3
màu cơ bản, một bit dùng để thay đổi cường độ sáng theo bảng sau:
Bài tập lớn môn Cơ sở lập trình 2 Page 11
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Color Itensity bit R G B IRGB Value
Black(đen) 0 0 0 0 0000
Blue(xanh da trời) 0 0 0 1 0001
Green(xanh lá cây) 0 0 1 0 0010
Cyan(xanh tươi) 0 0 1 1 0011
Red(đỏ đậm) 0 1 0 0 0100
Magenta(đỏ tươi) 0 1 0 1 0101
Brown(nâu) 0 1 1 0 0110
White(trắng) 0 1 1 1 0111
Gray(xám) 1 0 0 0 1000
Bright Blue 1 0 0 1 1001
Bright green 1 0 1 0 1010
Bright Cyan 1 0 1 1 1011
Bright Red 1 1 0 0 1100
Bright magenta 1 1 0 1 1101
Yellow(vàng) 1 1 1 0 1110
Bright White(trắng
sáng)

1 1 1 1 1110
Mỗi trang màn hình gồm 80*25 kí tự, do đó cần 80*25*2=4000 byte. Thực tế mỗi trang
được phân bố 4096=0x1000 byte. Như vậy:
Trang màn hình thứ nhất bắt đầu từ địa chỉ 0xB800:0x0000.
Trang màn hình thứ hai bắt đầu từ địa chỉ 0xB800:0x1000.
Trang màn hình thứ ba bắt đầu từ địa chỉ 0xB800:0x2000.
Trang màn hình thứ tư bắt đầu từ địa chỉ 0xB800:0x3000.
1.4 Cách tính địa chỉ của một ví trí (x, y) trên màn hình.
Địa chỉ (x, y) = B800h:0000h + (x*Số cột*2 + y*2).
Ví dụ: Với màn hình 80 cột x 25 dòng, ta có:
Địa chỉ (x, y) = B800h:0000h + (x*160 + y*2 ).
1.5 Cách cắt và lưu một vùng hay toàn bộ màn hình :
1.5.1 Hàm gettext( ):
Công dụng: Hàm gettext dùng để copy văn bản trên màn hình ở chế độ textmode
vào bộ nhớ.
Khai báo: int gettext(int left, int top, int right, int bottom, void*destin);
Hàm này lưu nội dung của đoạn văn bản trên màn hình nằm trong một hình chữ nhật
có tọa độ được chỉ ra là (left,top) và (right,bottom) ở trong vùng nhớ được trỏ bởi con
trỏ destin.
Hàm gettext đọc nội dung dữ liệu trong hình chữ nhật trong bộ nhớ một cách liên tục
tuần tự từ trái sang phải từ trên xuống dưới.Tất cả tọa độ ở đây điều là tọa độ tuyệt đối.
Đối với màn hình 25 hàng 80 cột thì tọa độ (1,1) là điểm nằm ở gốc trên bên trái, điểm
(80,1) là điểm ở gốc trên bên phải, điểm (1,25) là điểm ở góc dưới bên trái và điểm
(80,25) là điểm ở góc dưới bên phải.
Mỗi một vị trí trên màn hình được lưu mất 2 bytes trong bộ nhớ:
Byte đầu tiên lưu ký tự trong ô đó.
Byte thứ hai dùng để chỉ thuộc tính màn hình của ô đó.
Bài tập lớn môn Cơ sở lập trình 2 Page 12
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Không gian bộ nhớ yêu cầu để lưu một hình chữ nhật có w cột (độ rộng) và h dòng

(chiều cao) được tính theo công thức: bytes = (h rows) x (w columns) x 2
Kiểu trả về của hàm là: Nếu thành công sẽ trả về 1.
Nếu báo lỗi sẽ trả về 0.
1.5.2 Hàm puttext( ):
Công dụng: Hàm puttext dùng để lấy dữ liệu từ bộ nhớ đổ ra trở lại màn hình
khi trước đó mình đã lưu.
Khai báo: int puttext(int left, int top, int right, int bottom, void*source);
Hàm này lấy dữ liệu từ vùng nhớ do con trỏ source trỏ tới và xuất ra màn hình
trên một hình chữ nhật có tọa độ được chỉ ra là (left,top) và (right,bottom).
Hàm puttext lấy dữ liệu ở chế độ văn bản trong bộ nhớ và xuất trực tiếp ra màn
hình.
Kiểu trả về của hàm là: Nếu thành công sẽ trả về một số khác 0.
Nếu báo lỗi trả về 0.
Chương 2: Danh sách liên kết đơn – đôi và Ứng dụng:
2.1 Khái niệm và mô tả:
Danh sách là một tập hợp hữu hạn các phần tử có cùng kiểu. Số phần tử của danh sách
gọi là độ dài danh sách. Nếu độ dài danh sách bằng không thì đó là danh sách rỗng. Một
tính chất quan trọng của danh sách là các phần tử của danh sách có thứ tự tuyến tính
theo vị trí.
Việc sử dụng các kiểu dữ liệu tĩnh như kiểu số nguyên, số thực, ký tự, mảng, tập hợp…
đều có thể giải quyết hầu hết các bài toán. Nhưng việc sử dụng kiểu dữ liệu tĩnh trong
nhiều trường hợp sẽ gây khó khăn cho việc biểu diễn thông tin. Ví dụ như Khi ta lập
một chương trình quản lý mà bản thân phần tử chưa được biết trước, nếu sử dụng
mảng( cấp phát tĩnh) thì ta sử dụng số phần tử là tối đa. Như vậy sẽ có rất nhiều vùng
nhớ được cấp phát nhưng không bao giờ dùng đến. Do đó, nhằm đáp ứng nhu cầu biểu
diễn thông tin trong thực tế một cách chính xác và hiệu quả, người ta cần xây dựng các
cấu trúc dữ liệu linh động hơn, có thể thay đổi kích thước, cấp phát và giải phóng bộ
nhớ bất cứ khi nào cần thiết trong thòi gian chương trình thực thi. Đó chính là các cấu
trúc dữ liệu linh động.
2.2 Các đặc trưng, ưu khuyết điểm khi thao tác (tìm, thêm, xóa, sửa, …):

2.2.1 Danh sách liên kêt đơn:
Cấu trúc tự trỏ được dùng để xây dựng danh sách liên kết, đó là một nhóm cấu trúc
có những tính chất sau:
 Biết địa chỉ cấu trúc đầu đang được lưu trữ trong một con trỏ nào đó.
 Trong mỗi cấu trúc (trừ cấu trúc cuối) chứa địa chỉ của cấu trúc tiếp theo của
danh sách
 Cấu trúc cuối chứa hằng NULL
Ví dụ:
Bài tập lớn môn Cơ sở lập trình 2 Page 13
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Với danh sách này, ta có thể lần lượt duyệt từ cấu trúc đầu đến cấu trúc cuối theo
chiều từ trên xuống.
Nhóm liên kết theo chiều ngược lại có tính chất sau:
 Biết địa chỉ cấu trúc cuối.
 Trong mỗi cấu trúc( trừ cấu trúc đầu) đều chứa địa chỉ của cấu trúc trước đó.
 Cấu trúc đầu chứa hằng NULL.
Ví dụ:
Với danh sách này, ta có thể lần lượt duyệt từ cấu trúc cuối lên cấu trúc đầu
theo chiều từ dưới lên.
2.2.2 Danh sách liên kết đôi:
Ngoài hai cách trên ta còn có thể xây dựng các danh sách mà mỗi phần tử chứa hai
con trỏ trỏ đến phần tử trước và phần tử sau.
Ưu điểm:
Với loại danh sách này ta có thể truy cập theo cả hai chiều. Điều này giải quyết được
hạn chế của danh sách liên kết đơn, khi mà chúng ta luôn phải duyệt từ đầu cho đến
phần tử cần xét cho dù phần tử đó nằm ở gần cuối danh sách.
Nhược điểm:
Mỗi phần tử trong danh sách liên kết đôi cần tốn thêm một trường để lưu địa chỉ của
phần tử trước nó so với danh sách liên kết đơn.
Ví dụ:

2.2.3 Ưu và khuyết điểm của danh sách liên kết:
2.2.3.1 Ưu điểm:
• Cấu trúc danh sách liên kết là cấu trúc động, các nút đựơc cấp phát hoặc
bị giải phóng một cách linh hoạt (khi chương trình đang chạy). Chúng ta
có thể dùng biến động (hay dùng mảng) để cấp phát nút cho danh sách
liên kết.
• Danh sách liên kết rất thích hợp khi thực hiện tác vụ thêm nút, xóa nút,
lúc này chúng ta không phải dời nút giống như mảng mà chỉ cần hiệu
chỉnh lại trường next tại các nút đang thao tác. Thời gian thực hiện các
tác vụ này không phụ thuộc vào số nút hiện có trong danh sách liên kết.
2.2.3.2 Khuyết điểm:
• Vì mỗi nút phải chứa thêm trường next nên danh sách liên kết thường
không tối ưu về bộ nhớ.
• Tìm kiếm trong danh sách liên kết không nhanh vì chúng phải truy xuất
tuần tự từ đầu danh sách (bằng phương pháp tìm kiếm tuyến tính và phải
được sắp xếp trước khi thực hiện tìm kiếm nhị phân) .
Bài tập lớn môn Cơ sở lập trình 2 Page 14
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
2.3 Cài đặt cụ thể trong C, với thuộc tính Info có kiểu là chuỗi:
Xây dựng kiểu dữ liệu danh sách liên kết:
typedef struct
{
nodeptr pHead,pTail;
}LIST;
Khởi tạo danh sách:
void InitList(LIST &l)
{
l.pHead=l.pTail==NULL;
}
Tạo cấu trúc cho phần tử

Danh sách liên kết đơn:
typedef char* datatype;
typedef struct tag_node
{
datatype info;
tag_node *pNext;
}node,*nodeptr;
Danh sách liên kết đôi:
typedef char* datatype;
typedef struct tag_node
{
datatype info;
tag_node *pNext,*pPrev;
}node,*nodeptr;
Tạo nút mới:
 Cấp phát bộ nhớ cho một cấu trúc
 Nhập một biến cấu trúc vào vùng nhớ vừa cấp phát
 Gán địa chỉ của cấu trúc sau cho thành phần con trỏ ở cấu trúc trước.
Danh sách liên kết đơn
nodeptr makenode(datatpye s)
{
nodeptr p;
p=(nodeptr)malloc(sizeof(node));
if(!p) return NULL;
p->info=(char*)malloc(strlen(s)
+1);
strcpy(p->info,s);
p->pNext=NULL;
return p;
}

Danh sách liên kết đôi:
nodeptr makenode(datatpye s)
{
nodeptr p;
p=(nodeptr)malloc(sizeof(node));
if(!p) return NULL;
p->info=(char*)malloc(strlen(s)
+1);
strcpy(p->info,s);
p->pNext=p->pPrev=NULL;
return p;
}
Duyệt qua tất cả các phần tử của danh sách:
 Đưa con trỏ p về cùng cấu trúc với pHead bằng lệnh p=pHead;
 Để chuyển tiếp đến cấu trúc tiếp theo ta dùng lệnh : p=p->pNext;
 Dấu hiệu để biết đang xét phần tử cuối cùng của danh sách là:
p->pNext=NULL hay p=pTail.
Loại một phần tử ra khỏi danh sách:
Lưu trữ địa chỉ của phần tủ cần loại vào một con trỏ( để giải phóng bộ nhớ của
phần tử này).
Sửa để phần tử trước đó có địa chỉ của phần tử sau phần tử cần loại.
Giải phóng phần tử cần loại.
void DelNode(nodeptr p, LIST &l)
{
Bài tập lớn môn Cơ sở lập trình 2 Page 15
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
nodeptr q;
if(p->pNext!=NULL)
{
q=p->pNext;//phan tu can xoa

p->pNext=q->pNext;
delete q;
}
}
(tương tự cho danh sách liên kết đôi)
Bổ sung hoặc chèn một phần tử vào danh sách:
 Cấp phát bộ nhớ và nhập bổ sung.
 Sửa thành phần con trỏ trong các phần tử có liên quan để đảm bảo mỗi
phần tử chỉ chứa một địa chỉ của phần tử tiếp theo.
void InsertNode(datatype s,nodeptr p,LIST &l)
{
nodeptr q=makenode(s);//tao phan tu moi
q->pNext=p->pNext;
p->pNext=q;
}
Hàm cấp phát bộ nhớ:
void * malloc(unsigned n)
Hàm lấy trong thư viện alloc.h hoặc stdio.h.
Kích thước tính bằng số byte. Hàm sẽ đưa con trỏ về vị trí ô nhớ vừa được cấp phát
hoặc về NULL nếu không cấp phát đủ bộ nhớ cần thiết. Nếu kích thước ==0 thì trả về
NULL.
2.4 Nêu các lĩnh vực ứng dụng:
Ứng dụng quan trọng nhất của danh sách liên kết là tạo menu .
Ngoài ra, trong thực tế, kiểu dữ liệu danh sách còn được dùng khi cần lưu thông tin
của tất cả sinh viên trong lớp học, tất cả nhân viên trong công ty,danh sách các
cuốn sách trong thư viện….hay đơn giản là một dãy các số nguyên khi ta cần giải
quyết một bài toán nào đó trên máy tính.
Bài tập lớn môn Cơ sở lập trình 2 Page 16
Sơ lược về bộ nhớ màn hình-Danh sách liên kết
Tài liệu tham khảo:

• Cẩm nang lập trình (Nguyễn Minh San, Hoàng Đức Hải), tập 1 & 2.
• Bài tập ngôn ngữ và lập trình C (Nguyễn Thị Thanh Thủy).
• Kỹ thuật lập trình C ( Phạm Văn Ất).
• Cấu trúc dữ liệu ứng dụng và cài đặt bằng C ( Nguyễn Hồng Chương).
Bảng phân công cụ thể:
PHẦN LÝ THUYẾT:
 Nguyễn Hữu Tài phụ trách phần “Cấu trúc bộ nhớ màn hình Textmode, cách tính
địa chỉ một điểm trên màn hình ”.
 Nguyễn Hữu Trung phụ trách phần “Các hàm truy cập trực tiếp bộ nhớ”.
 Nguyễn Đức Anh Toàn phụ trách phần “Cắt và lưu một vùng hay toàn bộ màn
hình”.
 Nguyễn Thị Kim Phụng phụ trách phần “Video Ram, các dạng địa chỉ segment,
offset… ”.
 ĐặngThị Kim Thúy phụ trách phần “Danh sách liên kết”.
PHẦN CHƯƠNG TRÌNH:
 Nguyễn Hữu Tài
 Nguyễn Hữu Trung
IN THE END
Bài tập lớn môn Cơ sở lập trình 2 Page 17

×