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()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

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>

<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 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

Tags: