cslt 1 Chuong 6+7
Chương 6: Cấu trúc động của dữ liệu
6.1. Biến động
6.1.1. Khái niệm
Các biến đã làm quen từ đầu chương trình là các biến có kiểu cơ sở (char, int, float, ...), kiểu mảng hay kiểu cấu trúc (struct, file, ...). Tất cả các biến này đều được xác định trước một cách rõ ràng khi khai báo biến và mô tả kiểu (nếu là biến kiểu cấu trúc). Khi dịch chương trình, địa chỉ của các biến nói trên được xác định ngay, không thay đổi - Người ta gọi đó là các biến tĩnh. Các biến tĩnh bao gồm 4 loại sau đây:
- Biến toàn cục (thuộc lớp cấp phát tĩnh): được chứa tại một vùng riêng của bộ nhớ - vùng dữ liệu, do con trỏ DS trỏ tới.
- Biến địa phương cấp phát tĩnh (static)
- Biến địa phương cấp phát tự động.
}
Chứa trong vùng ngăn xếp Stack, do con trỏ SS trỏ tới.
- Biến địa phương thanh ghi.
Chứa ở thanh ghi
Khi chạy chương trình, các biến tĩnh tồn tại trong suốt thời gian khối chương trình chứa khai báo biến thực hiện. Ví dụ, Các biến tĩnh được khai báo và mô tả trong chương trình chính sẽ tồn tại trong suốt thời gian chương trình chính thực hiện; các biến tĩnh được khai báo và mô tả trong hàm sẽ tồn tại mỗi khi hàm đó được gọi.
Ngoài ra, trong C, có thể sử dụng một loại biến khác được tạo ra khi chạy chương trình, gọi là biến động - chúng không được xác định từ trước và không có tên, chỉ biết địa chỉ để truy nhập thông qua con trỏ.
Dễ thấy, dùng biến tĩnh sẽ tốn bộ nhớ hơn vì chúng phải tạo ra ngay từ đầu, còn dùng biến động thì khi nào cần đến đâu, cấp phát đến đó. Ví dụ: Phải lưu một dãy số n phần tử (n≤100), nếu dùng mảng, sẽ phải tạo ra mảng float x[100]; nhưng thực tế, n = 2 thì thừa đến 98 phần tử không sử dụng đến; Trong khi đó, dùng biến động, có thể tạo ra đúng n=2 biến động.
6.1.2. Tạo biến động
Việc tạo ra và giải phóng biến động được thực hiện nhờ hai hàm chuẩn malloc() và calloc() có sẵn trong tệp tiêu đề STDLIB.H, với cú pháp như sau:
(kiểu_dữ_liệu_cơ_sở *) malloc(số_byte)
Trong đó:
- kiểu_dữ_liệu_cơ_sở: là một trong các kiểu dữ liệu cơ sở như int, char, float, ...
- số_byte: là một số nguyên để chỉ độ dài của khối bộ nhớ được cấp phát cho biến động
Hàm yêu cầu cấp phát một khối bộ nhớ có độ dài bằng số_byte để chứa các dữ liệu có kiểu là kiểu_dữ_liệu_cơ_sở. Giá trị của hàm là một địa chỉ - địa chỉ đầu của khối bộ nhớ được cấp phát cho các biến động.
Ví dụ:
(int *) malloc(100) sẽ cấp phát khối bộ nhớ 100 bytes để chứa 50 phần tử kiểu int (vì dữ liệu kiểu int chứa ở 2 bytes) .
(float *) malloc(100) sẽ cấp phát khối bộ nhớ 100 bytes để chứa 25 phần tử kiểu float (vì dữ liệu kiểu float chứa ở 4 bytes).
Nếu yêu cầu cấp phát bộ nhớ động để chứa dữ liệu kiểu cấu trúc thì dùng hàm calloc():
(kiểu_dữ_liệu_cấu_trúc *) calloc(n, kích_thước_bản_ghi )
Trong đó:
n : là số bản ghi;
Kích_thước_bản_ghi : là kích thước một bản ghi của kiểu dữ liệu cấu trúc.
Ví dụ:
struc sophone
{ char hoten[30];
long int sodt;
}x ;
(struct sophone *) calloc(10, size(struct sophone));
Hàm này sẽ cấp phát bộ nhớ cho 10 bản ghi, mỗi bản ghi gồm hai phần tử (trường) là x.hoten và x.sodt.
6.1.3. Truy nhập biến động
Thứ nhất, biến động không có tên để truy nhập qua tên;
Thứ hai, các hàm malloc() và calloc() tạo ra biến động nhưng chỉ cho địa chỉ của khối biến động vừa tạo. Vì thế, chỉ có thể truy nhập biến động thông qua một cách duy nhất là sử dụng con trỏ.
Để truy nhập biến động qua con trỏ, phải khai báo con trỏ là một biến tĩnh; Sau đó cho con trỏ trỏ tới địa chỉ khối bộ nhớ của biến động cần truy nhập bằng lệnh gán và truy nhập đến từng phần tử thông qua con trỏ.
Các biến động được tạo ra trong chương trình thì cũng có thể được giải phóng theo yêu cầu của người lập trình. Khi cần giải phóng biến động, ta dùng hàm mẫu free() có sẵn trong tệp tiêu đề STDLIB.H, cú pháp như sau:
free(con_trỏ);
Trong đó: con_trỏ là biến con trỏ chỉ tới khối bộ nhớ chứa các biến động cần giải phóng để thu hồi bộ nhớ.
Ví dụ 1: Nhập vào một dãy n số nguyên (n cho từ bàn phím) , chứa vào biến động, rồi hiển thị lại dãy số từ các biến động đó.
#include <stdio.h>
#include <stdlib.h>
void main()
{ int i, n, *pt, *temp;
printf(“Số phần tử của dãy n = “); scanf(“%d”, &n);
pt = (int *) malloc(n*sizeof(int));
temp = pt;
clrscr();
for (i=1 ; i<=n; i++)
{printf(“Phần tử thứ %d = ”, i);
scanf(“%d”,pt);
pt++;
}
/* Hiển thị lại dãy số */
clrscr();
pt=temp;
for (i=1 ; i<=n; i++)
{printf(“Phần tử thứ %d = %d”, i, *pt);
pt++;
}
getch();
free(pt);
return (0);
}
Ví dụ 2: Lập danh bạ điện thoại của 10 người, mỗi người biết: Họ tên và số điện thoại. Yêu cầu chứa vào biến động, hiển thị lại danh bạ từ các biến động đó.
#include <stdio.h>
#include <stdlib.h>
void main()
{
struct danhba
{ char hoten[30];
long int sophone;
};
struct danhba *p, *q;
p = (struct danhba *) calloc(10, sizeof(struct danhba));
q = p;
/*Nhập họ tên và số điện thoại */
for (i =1; i<= 10; i++)
{
printf(“Họ tên người thứ %d : ”,i); gets(p->hoten);
printf(“Số điện thoại : ”); scanf(“%ld”, p->sodt);
p++;
}
/*Hiển thị họ tên và số điện thoại */
clrscr();
printf(“
Danh bạ điện thoại
”);
for (i =1; i<= 10; i++)
{
printf(“
%-30s %ld ”, q->hoten, q->sodt );
q++;
}
printf(“
Bấm phím bất kì để tiếp tục
”);
getch();
}
6.2. Cơ chế tạo biến động
Các biến động được được tạo ra trong chương trình C sẽ được xếp vào một vùng nhớ còn rỗi được tổ chức theo kiểu ngăn xếp của bộ nhớ và được gọi là HEAP - bộ nhớ cấp phát động. Vùng nhớ rỗi là toàn bộ phần không gian nhớ chưa được huy động tới để ghi thông tin - vùng còn lại sau ba vùng nhớ chính: Vùng mã, vùng dữ liệu và vùng Stack; Vùng nhớ rỗi được thanh ghi ES trỏ tới.
C quản lí HEAP thông qua một con trỏ, gọi là con trỏ HEAP. Con trỏ HEAP luôn trỏ vào byte đầu tiên còn rỗi trong bộ nhớ. Mỗi lần gọi hàm malloc(), con trỏ HEAP được dịch chuyển về phía đỉnh của vùng nhớ rỗi một số byte tương ứng với kích thước của biến động mới được tạo ra.
Khi giải phóng bộ nhớ cấp phát động, bộ nhớ dành cho biến động được thu hồi. Rất có thể xảy ra hiện tượng phân đoạn (phân mảnh) khi thu hồi bộ nhớ, nghĩa là các khối nhớ của biến động không được giải phóng theo trình tự được tạo ra, hơn nữa, C không có cơ chế dồn chỗ để chống phân mảnh.
Có thể thấy rõ hơn về cơ chế tạo biến động trong phần 7.2. - Bản đồ bộ nhớ chương trình.
bài tập chương 6
1. Chỉ sử dụng các biến động để sắp xếp một dãy số.
2. Chỉ sử dụng các biến động để tính tích các phần tử trên đường chéo chính và trên đường chéo phụ của ma trận vuông.
3. Sử dụng các biến động hợp lí để ghi giá trị của 100.000 số trong dãy số Fibonacy rồi hiển thị một số khi biết thứ tự trong dãy.
Chương 7: các mô hình bộ nhớ của C
7.1. Thanh ghi (register)
Bộ xử lí điển hình nhất của máy tính là bộ vi xử lí do hãng Intel chế tạo, nó được coi là tiêu chuẩn. Bên trong CPU của hãng Intel có một số thanh ghi là một loại bộ nhớ đặc biệt phục vụ ngay trong quá trình thực thi các lệnh. Nhiệm vụ của thanh ghi là chứa địa chỉ toán hạng và một số kết quả sau khi thực hiện pháp toán. Các máy tính càng lớn và đắt tiền thường có số thanh ghi nhiều hơn các máy nhỏ và rẻ, các máy có ít thanh ghi phải sử dụng bộ nhớ chính để chứa kết quả trung gian. Tiền thân của các bộ vi xử lí Intel là 80xx, sau đó phát triển thành 80286, 80386, 80486 rồi đến Pentium. Trong quá trình phát triển của các vi xử lí, ngày càng: Số thanh ghi nhiều hơn, các đường truyền rộng hơn, tập lệnh nhiều thêm.
Xét các thanh ghi của bộ vi xử lí đơn giản nhất là 8086/8088. Bộ vi xử lí này có 14 thanh ghi, mỗi thanh ghi là một ô nhớ 16 bit. Các thanh ghi này bao gồm: AX, BX, CX, DX, SP, BP, SI, DI, CS, DS, ES, SS, IP và Flags (cờ).
7.1.1. Các thanh ghi đa năng: AX, BX, CX, DX
Đây là các thanh ghi nhiều công dụng, chẳng hạn như: ghi giá trị toán hạng, ghi kết quả trung gian, .... Mỗi thanh ghi đa năng đều gồm hai thanh 8 bit (byte cao - Hight và byte thấp - Low) tạo thành, đó là các thanh ghi có tên là:
AX (Accumulator)
AH
AL
BX (Base)
BH
BL
CX (Count)
CH
CL
DX (Data)
DH
DL
7.1.2. Các thanh ghi địa chỉ đoạn: CS, DS, ES, SS
Các vi xử lí 8086/8088 đều có các thanh ghi 16 bit trong khi đường truyền dữ liệu là 20 bit. Để tạo dòng tín hiệu địa chỉ 20 bit ở các chân ra địa chỉ của bộ vi xử lí, người ta sử dụng cách thức phân chia bộ nhớ thành các đoạn (segment), mỗi đoạn 64 KB. Khi đó, địa chỉ trong máy tính sẽ gồm hai phần: Địa chỉ đoạn segment và địa chỉ trong đoạn offset (hay địa chỉ tương đối). Hai phần địa chỉ chứa trên hai thanh ghi khác nhau và:
Địa chỉ thực = địa chỉ segment * 16 + địa chỉ offset
Địa chỉ các segment được ghi trên các thanh ghi sau:
· CS (Code Segment): Là thanh ghi địa chỉ đoạn mã lệnh, chứa địa chỉ đoạn của chương trình đang thực hiện.
· DS (Data Segment): Là thanh ghi chỉ đoạn dữ liệu, chứa địa chỉ đoạn của vùng dữ liệu mà chương trình đang thực hiện sử dụng. Vùng này chứa các biến của chương trình.
· ES (Extra Segment): Là thanh ghi địa chỉ đoạn dữ liệu bổ sung mà chương trình đang thực hiện sử dụng tới. Vùng này cũng thường chứa các biến của chương trình.
· SS (Stack Segment): Là thanh ghi địa chỉ đoạn bộ nhớ xếp chồng (stack) của chương trình đang thực hiện.
Các thanh ghi địa chỉ đoạn sẽ ghi địa chỉ đoạn (segment) cho từng đối tượng sử dụng. Tuỳ thuộc cách bố trí các segment, C sẽ có mô hình bộ nhớ phù hợp.
7.1.3. Các thanh ghi con trỏ và chỉ số: IP, SP, BP, SI, DI
· IP (Instruction Pointer): Là thanh ghi chứa địa chỉ offset của lệnh sắp được thực hiện trong đoạn bộ nhớ có địa chỉ ghi trên thanh ghi CS - vì thế nó được gọi là con trỏ lệnh. Tuy vậy, một cặp thanh ghi CS:IP mới thực sự là con trỏ lệnh vì khi đó nó mới chứa đầy đủ thông tin về địa chỉ của của một lệnh trong bộ nhớ. Mỗi khi thực hiện xong một lệnh, bộ xử lí sẽ thay đổi giá trị IP để chỉ đến lệnh cần thực hiện tiếp theo.
· SP (Stack Pointer): Là thanh ghi địa chỉ hiện tại (đỉnh) trong bộ nhớ stack nên được gọi là con trỏ stack, nó luôn kết hợp với thanh ghi SS để tạo thành cặp SS:SP để trỏ tới đỉnh tức thời của stack. Sau mỗi thao tác cất vào (hoặc lấy ra), SP sẽ tự động tăng (hoặc giảm) giá trị bằng độ dài tương ứng của kiểu dữ liệu.
· BP (Base stack Pointer): Là thanh ghi con trỏ để đánh dấu Stack. Trong nhiều trường hợp cần sử dụng thanh ghi này, chẳng hạn như: truyền tham số thông qua Stack.
· SI (Source Index) và DI (Destination Index): Con trỏ chỉ số nguồn và con trỏ chỉ số đích. Các thanh ghi này dùng vào việc vận chuyển dữ liệu. Với các vi xử lí 16 bit, nó phải kết hợp với các thanh ghi segment DS và ES để tạo thành cặp DS:SI và ES:DI để trỏ tới nguồn và đích.
7.1.4. Thanh ghi cờ (Flags)
Flag là thanh ghi 16 bit, mỗi bit được sử dụng để biểu hiện một trạng thái của bộ vi xử lí tại một thời điểm nhất định trong quá trình thực hiện chương trình. Mỗi bit gọi là một cờ. Thường có các cờ:
· CF (Carry Flag) - cờ nhớ để báo tràn số khi nhớ
· PF (Parity Flag) - cờ chẵn lẻ để báo số bit trong byte dữ liệu là chẵn hay lẻ
· AF (Auxiliary Flag) - cờ bổ trợ
· ZF (Zero Flag) - cờ Zêro để báo kết quả phép tính bằng không hay không.
· SF (Sign Flag) - cờ dấu để xác định dấu của kết quả tính toán
· TF (Trap - single step Flag) - cờ chạy từng bước để báo cho máy chạy từng bước để có thể gỡ rối chương trình
· IF (Interrupt Flag) - cờ ngắt để thông báo cho bộ xử lí ngắt hay không
· DF (Direction Flag) - cờ hướng để báo hướng lấy dữ liệu là địa chỉ tăng hay giảm dần
· OF (Overflow Flag) - cờ tràn để báo có tràn số liệu
................
Các bộ vi xử lí đời sau có thay đổi số thanh ghi và phát triển độ rộng của thanh ghi thành 32 hoặc 64 bit. Chẳng hạn:
Bộ vi xử lí 80286 có 15 thanh ghi 16 bit - Bổ sung thêm một thanh ghi MSW (Machine Status Word); Ngoài ra, trong thanh ghi cờ có thêm 2 cờ mới NT (Nested Task) và IOPL (I/O Privilege Level) sử dụng trong chế độ bảo vệ.
Bộ vi xử lí 80386 có 32 thanh ghi 32 bit, do đó có thể đánh địa chỉ được 4 GB bộ nhớ vật lí 64 Tb bộ nhớ ảo.
Bộ vi xử lí 80486 có 32 thanh ghi 32 bit, là bộ vi xử lí 32 bit thực thụ, sử dụng công nghệ RISC với tần số đồng hồ tăng gấp đôi so với bộ vi xử lí 80386.
Bộ vi xử lí PENTIUM có bổ sung thêm 4 lệnh mới vào tập lệnh, trong đó, ba lệnh hỗ trợ cho đa xử lí, một lệnh vận chuyển dữ liệu có điều kiện. Các thanh ghi chứa dữ liệu là các thanh ghi 64 bit, có thể truyền song song 8 byte dữ liệu.
Khi Pentium được phát triển thành Pentium MMX (Multi-Media eXtentions), nó bổ sung 57 lệnh mới nhằm tăng tốc cho các chương trình ứng dụng truyền thông và đa phương tiện
7.2. bản đồ bộ nhớ của chương trình
Khi thực hiện một chương trình, C phân chia bộ thành ba vùng chính, đó là:
- Vùng mã: Là vùng chứa các câu lệnh và các hằng sử dụng trong chương trình. Vùng này được thanh ghi đoạn CS trỏ tới.
- Vùng dữ liệu: Là vùng chứa các biến tĩnh và biến toàn cục. Vùng này do thanh ghi đoạn DS trỏ tới.
- Vùng ngăn xếp (Stack): Là vùng chứa các biến địa phương. Vùng này do thanh ghi đoạn SS trỏ tới.
Ngoài ba vùng chính, còn một vùng khác để chứa các thành phần còn lại của chương trình (chẳng hạn như vùng nhớ cấp phát động). Vùng nhớ này được thanh ghi đoạn ES trỏ tới.
Địa chỉ từ thấp đến cao
Vùng mã
Vùng dữ liệu
Vùng ngăn xếp stack
Bộ nhớ đệm
Vùng nhớ cấp phát động
Phần bộ nhớ tự do
Bản đồ tổng quan bộ nhớ chương trình
Với các chương trình nhỏ tới mức có thể đặt cả ba vùng (vùng mã, vùng dữ liệu và vùng ngăn xếp) vào trong một đoạn 64 KB thì cả 3 thanh ghi CS, DS, SS đều trỏ tới cùng một đoạn.
Với các chương trình lớn, mỗi vùng của chương trình sẽ nằm trong một đoạn khác nhau; Khi đó các con trỏ CS, DS và SS trỏ tới các đoạn khác nhau.
7.3. Kiểu địa chỉ
7.3.1. Con trỏ near (gần)
Những chương trình nhỏ trong bộ nhớ, nó nằm gọn trong một segment 64 KB. Trường hợp này, không nhất thiết phải có các giá trị khác nhau cho từng segment một. Địa chỉ trong đoạn, tức offset, đủ để truy nhập tới bất cứ địa chỉ nào trong chương trình loại này. Một con trỏ 2 bytes có thể cho phép truy nhập bộ nhớ trong phạm vi 64 KB - một segment, được gọi là con trỏ near.
Trong trường hợp sử dụng con trỏ near, địa chỉ thực (hay địa chỉ vật lí) và địa chỉ trong đoạn là bằng nhau.
7.3.2. Con trỏ far (xa)
Khi chương trình sử dụng đến các địa chỉ vượt quá 64 KB - vượt quá một segment, chẳng hạn, con trỏ dữ liệu, thì con trỏ phải có đủ 4 bytes để: 2 bytes chứa địa chỉ segment, 2 bytes chứa địa địa chỉ offset. Những địa chỉ như thế, gọi là địa chỉ xa; Những con trỏ trỏ đến địa chỉ xa gọi là con trỏ far.
Có thể so sánh các con trỏ với nhau. Về mặt nguyên tắc lí thuyết, khi hai con trỏ có cùng một nội dung thì nó sẽ trỏ tới cùng một địa chỉ, tức là cùng một đối tượng. Tuy nhiên, khi sử dụng con trỏ far, mỗi địa chỉ được xác định bằng một cặp giá trị segment:offset thì, có thể có nhiều cặp segment:offset khác nhau đều là một địa chỉ. Vì thế, việc so sánh con trỏ khi đó là vô nghĩa.
Ví dụ: Có 2 giá trị của con trỏ là 0x4321:0x56 và 0x4000:0x3266 đều trỏ tới cùng một địa chỉ vật lí. Song, giá trị của con trỏ đầu tiên là 0x43210056 rất khác với con trỏ thứ hai là 0x40003266.
Khi lập trình có sử dụng đến các phép tính biến đổi địa chỉ chứa trong con trỏ, có thể gây tràn địa chỉ. Trường hợp này thường gặp nhất là khi cộng vào địa chỉ có phần offset gần tới địa chỉ FFFF.
Để giải quyết những vướng mắc đó, Turbo C sử dụng một loại con trỏ far đã được chuẩn hoá, gọi là con trỏ huge. Trong con trỏ huge, phần offset luôn có giá trị từ 0 đến 15. Như vậy địa chỉ vật lí (thực) chỉ có một cách biểu diễn duy nhất để có thể thực hiện các phép toán trên con trỏ, trong đó có hai phép toán quan trọng hơn cả là phép toán so sánh và phép toán số học.
Lưu ý rằng, khi thực hiện phép toán số học trên con trỏ huge, phải đảm bảo cho giá trị của offset nằm trong khoảng từ 0 đến 15.
7.3.3. Chọn con trỏ
Khi muốn nhất thiết sử dụng các con trỏ near, far hay huge, trong khai báo biến con trỏ, ta thêm các từ khoá near, far hay huge ở trước tên con trỏ. Ví dụ:
float near *p_number;
char far *p_char;
int huge *p_int;
Tuy vậy, với hai kiểu con trỏ near và far, không nên khai báo cụ thể sử dụng con trỏ kiểu nào vì C sẽ tự động chọn lấy kiểu con trỏ thích hợp nhất cho việc chạy chương trình.
7.4. Cấp phát bộ nhớ cho các biến
7.4.1. Biến địa phương
Biến địa phương được bố trí trong bộ nhớ kiểu xếp chồng - gọi là Stack. Trong RAM, Stack là một vùng nhớ được tổ chức theo kiểu LIFO (Last In , First Out - Vào sau, Ra trước). Cách bố trí này rất phù hợp với biến địa phương của các hàm trong C. Khi gọi một hàm có khai báo tham số và biến địa phương, các biến này sẽ được ghi trong Stack. Khi kết thúc một hàm được gọi sau cùng, các biến địa phương sử dụng trong hàm này sẽ được giải phóng sớm nhất, vì thế gọi là “Vào sau, Ra trước”. Điều đó lí giải cho tầm tác dụng cũng như thời gian tồn tại của các biến địa phương
Ngoài các biến địa phương tĩnh, các tham số truyền cho hàm cũng được coi là biến địa phương, được cất trữ trong stack mỗi khi hàm được gọi đến.
Các biến địa phương cấp phát tĩnh (với khai báo static) có thể giữ lại giá trị cho lần gọi hàm tiếp theo nhưng phải là với chính hàm đó chứ không phải hàm khác; Thế thì, khi khi kết thúc hàm, nó sẽ được di chuyển khỏi Stack để đưa sang vùng nhớ dữ liệu.
7.4.2. Biến toàn cục
Biến toàn cục được khai báo ngoài hàm, được cấp phát ngay khi liên kết các module chương trình, luôn được khởi tạo giá trị ban đầu bằng 0.
Biến toàn cục thuộc loại biến tĩnh và được bố trí trong vùng nhớ dữ liệu, được truy nhập đến nhờ các thanh ghi DS hoặc ES .
7.4.3. Biến động
Biến động được cấp phát trong khi thực hiện chương trình. Lúc gặp hàm malloc() calloc() thì biến động được tạo ra.
Biến động sẽ lưu trữ ở vùng nhớ HEAP.
7.4.3. Biến thanh ghi
Biến thanh ghi không sử dụng bộ nhớ RAM của máy tính mà sử dụng ngay các thanh ghi của CPU để lưu trữ dữ liệu. Các biến thanh ghi chỉ có độ dài 16 bit nên chỉ dùng cho các biến kiểu char, int. Biến thanh ghi không có địa chỉ nên không thể dùng con trỏ để truy nhập loại biến này.
7.5. Các mô hình bộ nhớ
Turbo C có 6 mô hình tổ chức bộ nhớ. Mỗi mô hình có một giới hạn riêng về độ lớn cho từng vùng, đồng thời, nó cũng xác định luôn cách tham chiếu để truy nhập tới từng vùng trong chương trình. Việc chọn mô hình tổ chức nào là do yêu cầu của công việc và thực hiện ấn định mô hình từ thực đơn options, cách thực hiện như sau:
Options->Compiler->Model:
Tiny/ Small /Medium/ Compact/ Large/ Huge
Đặc trưng của các mô hình được tóm tắt trong bảng sau:
Tiny
Small
Medium
Compact
Large
Huge
Vùng mã
64K
64K
1Mb
64K
1Mb
1Mb
Vùng dữ liệu
64K
64K
64K
64K
64K
1Mb
Vùng ngăn xếp
64K
64K
64K
64K
64K
64K
Vùng HEAP
64K
64K
64K
1Mb
1Mb
1Mb
HEAP tạo bởi malloc(), calloc()
near
near
near
far
far
far
HEAP tạo bởi farmalloc()
Không
Có
Có
Ngầm định
Ngầm định
Ngầm định
Con trỏ mã
near
near
far
near
far
far
Con trỏ dữ liệu
near
near
near
far
far
far
7.5.1. Mô hình Tiny
Là mô hình nhỏ nhất của bộ nhớ với tổng bộ nhớ cho cả 4 vùng phải không vượt quá 64 Kb để chứa trong cùng một đoạn. Cả 4 thanh ghi segment CS, DS, SS, ES chứa cùng một giá trị để trỏ tới cùng một đoạn. Con trỏ gần được sử dụng cho mọi thứ.
Mô hình này rất lí tưởng cho các chương trình nội trú hay các bài toán đơn giản. Có thể dịch chương trình này thành tệp .COM nhờ trình dịch EXE2BIN của DOS.
7.5.2. Mô hình Small
Là mô hình bộ nhớ ngầm định của C với vùng mã lệnh chứa riêng trong một segment 64 Kb, 3 vùng còn lại chứa kết hợp trong một segment nên tổng độ dài phải không quá 64 KB. Con trỏ near được sử dụng thường xuyên trừ khi có khai báo con trỏ far một cách tường minh để sử dụng bộ nhớ cấp phát động xa bởi farmalloc();
7.5.3. Mô hình Medium
Là mô hình thiết kế cho chương trình có nhiều mã lệnh và ít dữ liệu. Có một giới hạn 64 Kb cho mã trong mỗi tệp, tuy nhiên có thể liên kết giữa các tệp để có một chương trình có vùng mã lớn hơn 64 Kb. Ba vùng còn lại của chương trình được chứa kết hợp trong một segment nên tổng độ dài phải không quá 64 KB.
7.5.4. Mô hình Compact
Kích thước phải nhỏ hơn 64 Kb, nhưng mỗi phần mã, dữ liệu, ngăn xếp và HEAP đều được ghi trong các đoạn riêng của chúng.
Trong mô hình compact, con trỏ near được dùng cho mã và con trỏ far dùng cho dữ liệu.
7.5.5. Mô hình Large
Mô hình này tương tự như mô hình Compact nhưng cho phép kích thước mã vượt quá 64 Kb và do đó, con trỏ mã là con trỏ far.
Các chương trình lớn đều phải sử dụng tới mô hình tổ chức này.
7.5.6. Mô hình Huge
Là mô hình lớn nhất có thể có của C. Cả mã và dữ liệu đều có thể vượt quá 64 Kb và do đó con trỏ sử dụng cho mã và dữ liệu là con trỏ far. Vùng ngăn xếp vẫn khống chế trong một đoạn 64 Kb.
Phần phụ lục
Phụ lục 1: Bảng mã ASCII
(American Standard Code for Information Interchanges)
- Phần mã từ 0 đến 31 là mã các kí tự điều khiển, không in ra được;
- Phần mã từ 32 đến 127 là các mã cố định cho các kí tự, các kí tự này đều có sẵn trên bàn phím. Các kí tự cố định được kê ở bảng dưới đây;
- Phần mã từ 128 đến 255 là các mã mở rộng, dùng để mã các kí tự riêng.
Mã 16
<cột,dòng>
0
1
2
3
4
5
6
7
0
<NUL>
0
<DLE>
16
Space
32
0
48
@
64
P
80
'
96
112
1
<SOH>
1
<DC1>
17
!
33
1
49
A
65
Q
81
a
97
q
113
2
<STX>
2
<DC2>
18
“
34
2
50
B
66
R
82
98
114
3
♥-ETX
3
<DC3>
19
#
35
3
51
C
67
S
83
c
99
115
4
♦-EOT
4
<DC4>
20
$
36
4
52
D
68
T
84
d
100
116
5
♣-ENQ
5
<NAK>
21
%
37
5
53
E
69
U
85
101
u
117
6
♠-ACK
6
<SYN>
22
&
38
6
54
F
70
V
86
f
102
v
118
7
<BEL>
7
<ETB>
23
‘
39
7
55
G
71
W
87
103
w
119
8
<BS>
8
<CAN>
24
40
8
56
H
72
X
88
h
104
x
120
9
<HT>
9
<EM>
25
41
9
57
I
73
Y
89
105
y
121
A
<LF>
10
<SUB>
26
*
42
:
58
J
74
Z
90
j
106
z
122
B
<VT>
11
<ESC>
27
+
43
59
K
75
[
91
k
107
{
123
C
<FF>
12
<FS>
28
,
44
<
60
L
76
\
92
l
108
124
D
<CR>
13
<GS>
29
-
45
=
61
M
77
]
93
109
}
125
E
<SO>
14
<RS>
30
.
46
62
N
78
^
94
110
~
126
F
<SI>
15
<US>
31
47
?
63
O
79
_
95
111
<Del>
127
Phụ lục 2: các tệp hệ thống của Turbo C 2.0
(Chứa trong khoảng 2 đĩa 1.2M)
STT
Tên tệp
Chức năng
1
INSTALL.EXE
Cài đặt TC
2
README.COM
Vài điều cần biết về TC
3
TCHELP.TCH
Các dòng hướng dẫn khi chạy TC
4
TCHELP.COM
Quản lí tệp TCHELP.TCH
5
THELP.DOC
Hướng dẫn chạy tệp TCHELP.COM
6
TC.EXE
Soạn thảo và dịch chương trình TC
7
TCCONFIG.EXE
Chuyển các tệp cấu hình từ version trước
8
MAKE.EXE
Quản lí dự án
9
GREP.COM
Tìm kiếm xâu trong các tệp
10
TOUCH.COM
Sửa lại ngày cập nhật vào tệp
11
TCC.EXE
Dịch trực tiếp từ MS-DOS
12
CPP.EXE
Quan sát hiệu ứng tiền xử lí
13
TCINST.EXE
Thiết kế môi trường TC
14
TLINK.EXE
Kết nối chương trình của TC
15
THELP.DOC
Giải đáp tổng quát
16
C0T.OBJ
Các mã khởi động liên kết kiểu TINY
17
C0S.OBJ
Các mã khởi động liên kết kiểu SMALL
18
C0M.OBJ
Các mã khởi động liên kết kiểu MEDIUM
19
C0L.OBJ
Các mã khởi động liên kết kiểu LARGE
20
C0C.OBJ
Các mã khởi động liên kết kiểu COMPACT
21
C0H.OBJ
Các mã khởi động liên kết kiểu HUGE
22
CT.LIB
Các hàm thư viện kiểu TINY
23
CS.LIB
Các hàm thư viện kiểu SMALL
24
CM.LIB
Các hàm thư viện kiểu MEDIUM
25
CL.LIB
Các hàm thư viện kiểu LARGE
26
CC.LIB
Các hàm thư viện kiểu COMPACT
27
CH.LIB
Các hàm thư viện kiểu HUGE
28
MATHS.LIB
Các mã hàm toán học kiểu SMALL
29
MATHM.LIB
Các mã hàm toán học kiểu MEDIUM
30
MATHC.LIB
Các mã hàm toán học kiểu COMPACT
31
MATHL.LIB
Các mã hàm toán học kiểu LARGE
32
EMU.LIB
Chuyển đổi tính bằng phần mềm hay 8087
33
GRAPHICS.LIB
Các mã lệnh trong chế độ đồ họa
34
FP87.LIB
Các hàm thư viện tính bằng 8087
35
TLIB.EXE
Thay đổi các tệp thư viện *.LIB
36
OBJXREP.COM
Tham khảo các hàm trong tệp .OBJ
37
UNPACK.COM
Mở các tệp nén .ARC
38
INIT.OBJ
Liên kết với Turbo Prolog
Các tệp nén (*.ARC), gồm:
STT
Tên tệp
Chức năng
1
BGI.ARC
Gồm các tệp BGI và CHR liên quan đến Card màn hình và Fonts chữ
2
BGIDEMO.C
Tệp ví dụ về đồ hoạ
3
STARTUP.ARC
Liên kết C với Assembler
4
EXAMPLES.ARC
CPASDEMO.PAS
CPASDEMO.C
CPASDEMO.TC
CBAR.C
PBAR.PRO
WORDCNT.C
WORDCNT.DAT
MCALC.ARC
Nén các tệp:
Viết bằng Pascal 4.0 giao diện với C
Viết bằng TC 2.0 giao diện với Pascal 4.0
Tệp cấu hình cho TC.EXE liên kết với Pascal 4.0
Giao diện với C
Giao diện với C
Mô tả cách thức chạy Debug
Mô tả cách thức chạy Debug
Các tệp tạo ra bảng tính giống như Lotus
Phụ lục 3: thư viện các hàm chuẩn
STT
Tên tệp
Chức năng
1
ALLOC.H
Memory management functions and variables.
Chứa các hàm và các biến quản lí bộ nhớ
2
ASSERT.H
assert macro
3
BIOS.H
Access to bios services.
4
CONIO.H
Direct MS-DOS console input/output.
5
CTYPE.H
Defines the ctype macros.
6
DIR.H
Defines structures, macros, and functions for dealing with directories and pathnames.
7
DOS.H
Defines structs, unions, macros, and functions for dealing with MSDOS and the Intel iAPX86 icroprocessor family.
8
ERRNO.H
Defines the system error variable errno and the error numbers set by system calls. Errors which exist in Unix(tm) but not MSDOS have value -1.
9
FCNTL.H
Define flag values accessible to open.
10
FLOAT.H
Defines implementation specific macros for dealing with floating point.
11
GRAPHICS.H
Definitions for Graphics Package.
12
IO.H
Definitions for low level I/O functions.
13
LIMITS.H
Defines implementation specific limits on type values.
14
MATH.H
Definitions for the math floating point package.
15
MEM.H
Memory manipulation functions
16
PROCESS.H
Symbols and structures for process management.
17
SETJMP.H
Defines typedef and functions for setjmp/longjmp
18
SHARE.H
File sharing mode for use with sopen. See DOS function 3Dh for definition.
19
SIGNAL.H
Definitions for ANSI defined signaling capability
20
STDARG.H
Definitions for accessing parameters in functions that accept a variable number of arguments.
21
STDDEF.H
Definitions for common types, NULL, and errno.
22
STDIO.H
Definitions for stream input/output.
23
STDLIB.H
Definitions for common types, variables, and functions.
24
STRING.H
Definitions for memory and string functions.
25
VALUES.H
Symbolic names for important constants, including machine dependencies. ASystem V compatible header.
26
TIME.H
Struct and function declarations for dealing with time.
27
STAT.H
Definitions used for file status functions
28
TYPES.H
Types for dealing with time.
29
TYMEB.H
Struct and function declarations for ftime().
danh mục tài liệu tham khảo
1. Phạm Văn ất - Kĩ thuật lập trình C cơ sở và nâng cao. NXB Thống kê - 2003.
2. Quách Tuấn Ngọc - Ngôn ngữ lập trình C. NXB Thống kê - 2003
3. Bùi Thế Tâm - Giáo trình Turbo C / C++. NXB Giao thông vận tải - 2003
4. Nguyễn Đình Tê & Hoàng Đức Hải - Lí thuyết và bài tập ngôn ngữ C - Tập 1 & 2. NXB Giáo dục - 1998
5. Ngô Trung Việt - Ngôn ngữ lập trình C và C++. NXB Thống kê - 2003
6. Brian W. Kernighan & Dennish M.Ritchie - The C programming language. Prentice hall international editions - 1997.
7. James Lantonakos & Kenneth C.Mansfield JR - Application programming in Structures C. Prentice hall international editions - 1996.
mục lục
Chương 1: Kĩ thuật lập trình cơ bản
1
1.1. Thuật toán
1
1.1.1. Khái niệm thuật toán
1
1.1.2. Biểu diễn thuật toán
2
1.1.3. Các cấu trúc cơ bản của thuật toán
3
1.2. Chương trình và ngôn ngữ lập trình
5
1.2.1. Chương trình
5
1.2.2. Ngôn ngữ lập trình
6
1.3. Thiết kế một chương trình máy tính
8
1.3.1. Kĩ thuật thiết kế trên xuống
8
1.3.2. Kĩ thuật chương trình con
9
1.3.3. Kĩ thuật đệ quy
15
1.4. Trình tự giải bài toán trên máy tính
18
1.4.1. Xác định bài toán
18
1.4.2. Xác định cấu trúc dữ liệu của bài toán
18
1.4.3. Tìm cách giải và xây dựng thuật toán
18
1.4.4. Viết chương trình
18
1.4.5. Chạy thử và hiệu chỉnh chương trình
18
1.4.6. Giải bài toán
19
1.4.7. Đánh giá kết quả
19
1.4.8. Hướng dẫn và bảo trì
19
1.5. Số có độ chính xác hữu hạn
20
Câu hỏi và bài tập chương 1
22
Chương 2: Lập trình căn bản trên C
23
2.1. Làm quen với Turbo C
23
2.1.1. Khởi động và thoát khỏi
23
2.1.2. Môi trường làm việc của Turbo C
24
2.2. Các yếu tố cơ bản trong Turbo C
27
2.2.1. bảng chữ cái
27
2.2.2. Từ khoá
27
2.2.3. Tên
27
2.2.4. Chú thích
27
2.2.5. Các kiểu dữ liệu cơ sở
28
2.2.6. Các đại lượng
30
2.2.7. Biểu thức
35
2.3. Cấu trúc của một chương trình C
39
2.3.1. Làm quen với chương trình C
40
2.3.2. Cấu trúc chung của một chương trình C
40
2.4. Khối lệnh
41
2.5. Các lệnh cơ bản của C
43
2.5.1. Các phép gán, vào - ra dữ liệu.
Chương trình có cấu trúc tuần tự
43
2.5.1.1. Lệnh gán và phép toán tăng giảm 1
43
2.5.1.2. Xuất thông tin
45
2.5.1.3. Nhập dữ liệu từ bàn phím
49
2.5.1.4. Chương trình có cấu trúc tuần tự
54
2.5.2. Lệnh điều khiển rẽ nhánh
54
2.5.2.1. Lệnh if ... else
54
2.5.2.2. lệnh switch
57
2.5.3. Lệnh điều khiển chu trình
61
2.5.3.1. Lệnh for
62
2.5.3.2. Các lệnh break, continue và goto
65
2.5.3.3 Lệnh while
69
2.5.3.4. lệnh do ... while
72
Bài tập chương 2
75
Chương 3: Mảng, xâu và con trỏ
78
3.1. Mảng và xâu
78
3.1.1. Mảng
78
3.1.2. Xâu
83
3.1.2.1. Khái niệm
83
3.1.2.2. Khai báo biến xâu
83
3.1.2.3. Truy nhập đến các kí tự trong xâu
83
3.1.2.4. Một số hàm mẫu với xâu
85
3.2. Con trỏ
87
3.2.1. Khái quát về con trỏ
87
3.2.1.1. Khái niệm
87
3.2.1.2. Định vị con trỏ
88
3.2.2. Các phép toán trên con trỏ
89
3.2.2.1. Phép gán
89
3.2.2.2. Phép tăng giảm địa chỉ
90
3.2.2.3. Phép truy nhập bộ nhớ
91
3.2.2.4. Phép so sánh
92
3.2.3. Con trỏ và mảng
92
3.2.3.1. Con trỏ và mảng một chiều
92
3.2.3.2. Con trỏ và xâu
94
3.2.3.3. Con trỏ và mảng nhiều chiều
95
Bài tập chương 3
96
Chương 4: Hàm và Macro
98
4.1. Làm quen với hàm
98
4.1.1. Giới thiệu về hàm trong C
98
4.1.2. Cấu trúc tổng quát của một hàm
99
4.1.3. Phát biểu return
103
4.1.4. Nguyên tắc hoạt động của hàm
104
4.1.5. Sử dụng giá trị trả về một hàm
106
4.2. Truyền tham số cho hàm
109
4.2.1. Biến toàn cục và biến địa phương
109
4.2.2. Tham số hình thức của hàm
112
4.2.3. Truyền tham số
113
4.3. Hàm đệ quy
114
4.4. Macro
117
Bài tập chương 4
119
Chương 5: Kiểu dữ liệu có cấu trúc
120
5.1. Khái niệm về kiểu dữ liệu có cấu trúc
120
5.2. Khai báo và truy nhập vào phần tử struct
120
5.2.1. Khai báo kiểu struct
120
5.2.2. Truy nhập vào phần tử struct
123
5.3. Mảng cấu trúc
125
5.3.1. Khai báo biến mảng cấu trúc
125
5.3.2. Truy nhập phần tử mảng cấu trúc
126
5.4. Dữ liệu kiểu enum và kiểu typedef
130
5.4.1. Kiểu enum
130
5.4.2. Định nghĩa kiểu typedef
132
5.5. Dữ liệu kiểu file
133
5.5.1. Khái niệm và phân loại tệp
133
5.5.2. Các bước xử lí tệp
134
5.5.3. Một số hàm dùng chung cho cả hai kiểu tệp
137
5.5.4. Tệp dữ liệu nhị phân
140
5.5.4.1. Tạo tệp nhị phân
140
5.5.4.2. Truy nhập tệp dữ liệu nhị phân
140
5.5.4.3. Truy nhập tệp dữ liệu struct
142
5.5.5. Tệp văn bản
145
5.5.5.1. Một số hàm xử lí tệp văn bản
145
5.5.5.2. Truyền tham số là tệp cho hàm
150
Bài tập chương 5
153
Chương 6: Cấu trúc động của dữ liệu
154
6.1. Biến động
154
6.1.1. Khái niệm
154
6.1.2. Tạo biến động
154
6.1.3. Truy nhập biến động
155
6.2. Cơ chế tạo biến động
157
Bài tập chương 6
159
Chương 7: Các mô hình bộ nhớ của C
160
7.1. Thanh ghi
160
7.1.1. Các thanh ghi đa năng: AX, BX, CX, DX
160
7.1.2. Các thanh ghi địa chỉ đoạn: CS, DS, ES, SS
160
7.1.3. Các thanh ghi con trỏ và chỉ số: IP, SP, BP, SI, DI
161
7.1.4. Thanh ghi cờ
161
7.2. Bản đồ bộ nhớ của chương trình
162
7.3. Kiểu địa chỉ
163
7.3.1. Con trỏ near
163
7.3.2. Con trỏ far
163
7.3.3. Chọn con trỏ
164
7.4. Cấp phát bộ nhớ cho các biến
164
7.4.1. Biến địa phương
164
7.4.2. Biến toàn cục
165
7.4.3. Biến động
165
7.4.4. Biến thanh ghi
165
7.5. Các mô hình bộ nhớ
165
7.5.1. Mô hình Tiny
166
7.5.2. Mô hình Small
166
7.5.3. Mô hình Medium
166
7.5.4. Mô hình Compact
166
7.5.5. Mô hình Large
166
7.5.6. Mô hình Huge
166
Phần phụ lục:
Phụ lục 1: Bảng mã ASCII
Phụ lục 2: Các tệp hệ thống của Turbo C
Phụ lục 3: Thư viện các hàm chuẩn của Turbo C
Tài liệu tham khảo
167
167
168
170
172
Bạn đang đọc truyện trên: AzTruyen.Top