Giáo trình C - Chương 4: Bộ nhớ và hiển thị kí tự
Các phép toán này có thể áp dụng cho dữ liệu kiểu int , char nh-ng không áp dụng
cho số float .
Toán tử & (khác với and logic &&) cần hai toán hạng có kiểu giống nhau . Các toán
hạng này đ-ợc and bit với bit . Toán tử & th-ờng dùng kiểm tra xem một bit cụ thể nào đó
có trị là bao nhiêu . Ví dụ để kiểm tra bit thứ 3 cuả biến ch có trị 1 hay 0 ta dùng phép toán :
ch &0x08;
thêm một
trình xử lí văn bản theo dòng . Trình xử lí này chỉ làm việc trên một dòng văn bản . Ta sẽ
tiến hành theo 2 b−ớc : đầu tiên là một ch−ơng trình cho phép ng−ời dùng gõ vào một dòng
50
và di chuyển con nháy tới lui . Có thể xoá kí tự nhờ di chuyển con nháy tới đó và ghi đè lên
nó . Ch−ơng trình nh− sau :
Ch−ơng trình 4-4 :
#include
#include
#define colmax 80
#define rarrow 77
#define larrow 75
#define video 0x10
#define ctrlc '\x03'
int col=0;
int far *fptr;
union REGS reg;
void main()
{
char ch;
void clear(void);
void cursor(void);
void insert(char);
fptr=(int far*)0xB8000000;
clear();
cursor();
while((ch=getch())!=ctrlc)
{
if (ch==0)
{
ch=getch();
switch (ch)
{
case rarrow : if (col<colmax)
++col;
break;
case larrow : if (col>0)
--col;
break;
}
}
else
if (col<colmax)
insert(ch);
cursor();
}
}
void cursor()
{
reg.h.ah=2;
reg.h.dl=col;
reg.h.dh=0;
51
reg.h.bh=0;
int86(video,®,®);
}
void insert(char ch)
{
*(fptr+col)=ch|0x0700;
++col;
}
void clear()
{
int j;
for (j=0;j<2000;j++)
*(fptr+j)=0x0700;
}
Để xoá màn hình ta điền số 0 vào vùng nhớ màn hình với thuộc tính 07 . Sau đó con
nháy đ−ợc di chuyển về đầu màn hình nhờ phục vụ ấn định vị trí con nháy nh− sau :
ngắt 10h
ah=0;
dh=số hiệu dòng
dl= số hiệu cột
bh=số hiệu trang , th−ờng là 0
Phát biểu switch dùng để đoán nhận các phím đ−ợc nhận là phím th−ờng hay phím
chức năng . Phím mũi tên dùng tăng giảm col và gọi hàm cursor() để di chuyển con nháy tới
đó . Nếu kí tự gõ vào là kí tự th−ờng , nó đ−ợc chèn vào nhờ hàm insert() .
6. Byte thuộc tính : Một kí tự trên màn hình đ−ợc l−u giữ bởi 2 byte : một byte là mã của kí
tự và byte kia là thuộc tính của nó . Byte thuộc tính đ−ợc chia làm nhiều phần , bit nào bằng
1 thì thì thuộc tính t−ơng ứng đ−ợc bật . Bit thứ 3 điều khiển độ sáng còn bit thứ 7 điều
khiển độ chớp nháy . Các bit còn lại là : 6 - thành phần đỏ của màu nền ; 5 - thành phần
green của màu nền ; 4 - thành phần blue của màu nền ; 2 - thành phần đỏ của màu chữ ; 1 -
thành phần green của màu chữ ; 0 - thành phần blue của màu chữ . Ta lập một ch−ơng trình
để điền đầy màn hình bằng các kí tự chớp nháy .
Ch−ơng trình 4-5 :
#include
#include
#define rowmax 25
#define colmax 80
void main()
{
int far *fptr;
int row,col;
char ch;
clrscr();
printf("Go vao mot ki tu , go lai de thay doi");
fptr=(int far*)0xB8000000;
while((ch=getche())!='x')
for (row=0;row<rowmax;row++)
52
for (col=0;col<colmax;col++)
*(fptr+row*colmax+col)=ch|0x8700;
}
Để bật chớp nháy ta để bit thứ 7 thành 1 , 3 bit màu nền 0 , 1 và 2 đ−ợc đặt trị 1 nên
nền sẽ là đen . Byte thuộc tính lúc này là 10000111 = 87h.
7. Ch−ơng trình điền thuộc tính : Để hiểu sâu hơn thuộc tính của kí tự ta xét ch−ơng trình
sau
Ch−ơng trình 4-6 :
#include
#include
#define rowmax 25
#define colmax 80
void main()
{
int far *fptr;
char ch,attr=0x07;
void fill(char,char);
clrscr();
printf("Go n cho chu binh thuong,\n");
printf("Go b cho chu xanh nuoc bien,\n");
printf("Go i cho chu sang,\n");
printf("Go c cho chu chop nhay,\n");
printf("Go r cho chu dao mau\n");
while((ch=getche())!='x')
{
switch (ch)
{
case 'n':attr=0x07;
break;
case 'b':attr=attr&0x88;
attr=attr|0x01;
break;
case 'i':attr=attr^0x08;
break;
case 'c':attr=attr^0x80;
break;
case 'r':attr=attr&0x88;
attr=attr|0x70;
break;
}
fill(ch,attr);
}
}
void fill(char ch,char attr)
{
int far *fptr;
int row,col;
fptr=(int far*)0xB8000000;
for (row=0;row<rowmax;row++)
53
for (col=0;col<colmax;col++)
*(fptr+row*colmax+col)=ch|attr<<8;
}
Trong hàm fill() ta có lệnh
*(fptr+row*colmax+col)=ch|attr<<8;
vì attr là kí tự nên phải dịch trái 8 bit tr−ớc khi kết hợp với ch .
8. Trở lại xử lí văn bản : Bây giờ chúng ta đã biết thuộc tính của kí tự và ta sẽ mở rộng
ch−ơng trình xử lí văn bản bằng cách thêm vào việc chèn và huỷ bỏ kí tự ,đổi màu .
Ch−ơng trình 4-7 :
#include
#include
#define colmax 80
#define rarrow 77
#define larrow 75
#define video 0x10
#define norm 0x07
#define blue 0x01
#define bkspc 8
#define altu 22
#define ctrlc '\x03'
int col=0;
int length=0;
int far *fptr;
union REGS reg;
void main()
{
char ch,attr=norm;
void clear(void);
void cursor(void);
void insert(char,char);
void del(void);
fptr=(int far*)0xB8000000;
clear();
cursor();
while((ch=getch())!=ctrlc)
{
if (ch==0)
{
ch=getch();
switch (ch)
{
case rarrow : if (col<length)
++col;
break;
case larrow : if (col>0)
--col;
break;
case altu : attr=(attr==norm)? blue:norm;
}
54
}
else
switch (ch)
{
case bkspc: if (length>0)
del();
break;
default : if (length<colmax)
insert(ch,attr);
}
cursor();
}
}
void cursor()
{
reg.h.ah=2;
reg.h.dl=col;
reg.h.dh=0;
reg.h.bh=0;
int86(video,®,®);
}
void insert(char ch,char attr)
{
int i;
for (i=length;i>col;i--)
*(fptr+i)=*(fptr+i-1);
*(fptr+col)=ch|attr<<8;
++length;
++col;
}
void del()
{
int i;
for (i=col;i<=length;i++)
*(fptr+i-1)=*(fptr+i);
--length;
--col;
}
void clear()
{
int j;
for (j=0;j<2000;j++)
*(fptr+j)=0x0700;
}
Khi gõ tổ hợp phím Alt+U sẽ lật biến attr qua lại giữa norm(thuộc tính 07) và blue
(cho chữ màu xanh - thuộc tính 01) . Hàm insert(0 có vòng lặp for dùng để thâm nhập trực
55
tiếp bộ nhớ và con trỏ far để dịch các kí tự sang trái khi cần chèn . Tiến trìmh dịch phải bắt
đầu từ cuối câu để tránh ghi đè lên .
Đ4. Các kiểu bộ nhớ trong C
1. Địa chỉ đoạn và offset : Trong C kiểu bộ nhớ là khái niệm để chỉ về l−ợng các phần bộ
nhớ khác nhau mà ch−ơng trình có thể chiếm . C cho phép 6 kiểu bộ nhớ là tiny , small ,
compact , medium , large và huge . Kiểu bộ nhớ mặc định là small .
Bộ vi xử lí dùng các thanh ghi 16 bit để ghi địa chỉ . Thanh ghi 16 bit l−u đ−ợc ffffh
byte hay 65536 hay 64 Kb địa chỉ . Vùng nhớ có kích th−ớc này gọi là đoạn . Để truy cập
địa chỉ nằm ngoài đoạn , bộ vi xử lí phải dùng hai thanh ghi là thanh ghi đoạn và thanh ghi
offset . Địa chỉ thực đ−ợc tính bằng cách dịch địa chỉ của thanh ghi đoạn sang trái 4 bit rồi
cộng với thanh ghi offset . Làm nh− vậy ta đánh địa chỉ đ−ợc fffffh hay 1048576 = 1Mb .
2. Hai loại chỉ thị của bộ vi xử lí : Bộ vi xử lí dùng hai kĩ thuật khác nhau để tham chiếu dữ
liệu trong bộ nhớ . Nếu vị trí cần tham chiếu nằm trong đoạn 64Kb và đoạn này đã đ−ợc chỉ
định trong thanh ghi đoạn thì bộ vi xử lí chỉ cần dùng một lệnh duy nhất để truy cập dữ liệu .
Cách này t−ơng ứng với việc dùng con trỏ near trong C và thực hiện rất nhanh . Trái lại nếu
bộ vi xử lí cần tham chiếu ô nhớ nằm ngoài đoạn thì đầu tiên nó phải thay đổi địa chỉ đoạn
và sau đoa là địa chỉ offset . Điều này t−ơng ứng với việc dùng con trỏ far trong C và thực
hiện khá chậm .
3. Các kiểu Compact , small , medium và large : Có 4 loại chỉ thị của bộ vi xử lí ứng với 4
kiểu bộ nhớ trong C
Kiểu Mã Dữ liệu
small near near
medium far near
compact near far
large far far
Nếu mã ch−ơng trình nằm gọn trong một đoạn 64 K và mã dữ liệu nằm gọn trong
một đoạn 64 K khác thì kiểu bộ nhớ small là thích hợp . Nếu mã ch−ơng trình lớn hơn 64 K
và mã dữ liệu nằm gọn trong một đoạn 64 K khác thì hãy dùng kiểu bộ nhớ medium. Nếu
mã ch−ơng trình nhỏ hơn 64 K và mã dữ liệu lớn hơn 64 K thì hãy dùng kiểu bộ nhớ
compact. Nếu cả mã ch−ơng trình và mã dữ liệu lớn hơn 64 K thì hãy dùng kiểu bộ nhớ
large .
4. Kiểu tyni và kiểu huge : Kiểu tyni đ−ợc dùng trong các tr−ờng hợp đặc biệt với l−ợng
bộ nhớ cho cả mã ch−ơng trình lẫn mã dữ liệu nằm gọn trong một đoạn . Kiểu này đ−ợc
dùng để tạo ra tập tin dạng *.com . Kiểu huge đ−ợc dùng chô một mục dữ liệu (th−ờng là
mảng ) mà bản thân nó lớn hơn 64K .
Đ5. Từ chứa danh mục thiết bị
Đây là một vùng bộ nhớ dài 2 byte nằm trong vùng nhớ thấp có địa chỉ tuyệt đối là
410h chứa thông tin về thiết bị đ−ợc nối với máy tính. Để truy cậo từ này ta dùng con trỏ far
. Con trỏ sẽ chỉ tới đoạn 0000 , địa xhỉ offset là 0410h và đ−ợc biểu diễn trong C là
00000410 hay 0x410
56
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
có
Số máy in ổ đĩa
đang có Không
Có lắp máy dùng
in nối tiếp RAM mạch
Có lắp game hệ thống
adaptor 00=16K
Số cổng nối tiếp 01=32K
Có lắp chíp 11=64K
DMA Kiểu màn hình
01=màu 40 cột
Số ổ đĩa 10=màu 80 cột
00 = 1 ổ 11=đơn sắc 80 cột
01 = 2 ổ
10 = 3 ổ
11 = 4 ổ
Để xem xét từng bit và nhóm bit trong từ này chúng ta sẽ dùng các toán tử bitweise .
Nói chung ta sẽ dịch từ chứa danh mục thiết bị sang phải và đ−a các bit cần quan tâm vào
phía phải của từ và che các bit không quan tâm ở phái trái bằng toán tử and . Ngoài từ chứa
danh mục thiết bị ta có thể đọc từ chứa kích th−ớc bộ nhớ tại địa chỉ 413h .
Ch−ơng trình 4-8 :
#define eqlist 0x410
#define memsiz 0x413
#include
#include
void main()
{
int far *fptr;
unsigned int eq,data;
clrscr();
fptr=(int far *)eqlist;
eq=*(fptr);
data=eq>>14;
printf("So may in la : %d\n",data);
if (eq&0x2000)
printf("Co may in noi tiep\n");
data=(eq>>9)&7;
printf("So cong noi tiep la :%d\n",data+1);
if (eq&1)
{
data=(eq>>6)&3;
printf("So dia mem la :%d\n",data);
}
else
57
printf("Khong co dia mem\n");
data=(eq>>4)&3;
switch (data)
{
case 1: printf("Man hinh mau 40 cot\n");
break;
case 2: printf("Man hinh mau 80 cot\n");
break;
case 3: printf("Man hinh don sac 80 cot\n");
}
fptr=(int far *)memsiz;
printf("Dung luong bo nho :%dKbyte\n",*(fptr));
getch();
}
File đính kèm:
Giao_Trinh_C_Chuong4.pdf

