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 (660.5 KB, 19 trang )
<span class="text_page_counter">Trang 1</span><div class="page_container" data-page="1">
<b>Macro được dùng để chỉ những hàm được viết ở phần Preprocessor (là các </b>
directive (chỉ thị), cung cấp chỉ lệnh tới bộ biên dịch để tiền xử lý thông tin trước khi bắt đầu biên dịch thực sự) thay vì đặt nó vào trong phần thực thi của file nguồn,mặt khác khi nói đến macro có 1 nghĩa khác nữa, ám chỉ đến tất cả những phần định nghĩa được viết trong phần Preprocessor. Trong quá trình tiền xử lí (pre-processor), các macro được sử dụng trong chương trình được thay thế bởi các khối câu lệnh tương ứng. Ta có thể định nghĩa macro bằng lệnh #define.
<small>// C program to illustrate macros</small>
<small> // Print the value of macro defined</small>
<small> printf("The value of LIMIT" " is %d",</small>
<small> LIMIT); return0;}</small>
Ta có đầu ra: Giá trị của LIMIT là 5.
Các macro giống như một đối tượng với một văn bản thay thế: Khi bộ tiền xử lý gặp lệnh này, bất kỳ sự xuất hiện nào nữa của định danh macro sẽ được thay thế bằng một đoạn văn bản mà chúng ta đã định nghĩa trước đó. Thơng thường thì tên định danh của macro sẽ được ghi bằng các chữ in hoa, sử dụng dấu gạch dưới để thể hiện khoảng trắng.
<i><b>Chương trình chạy in ra: My name is: Alex</b></i>
Các macro cũng có thể giống như đối tượng mà khơng có văn bản thay thếVí dụ:
Hàm(Function) là 1 khối lệnh thực hiện một chức năng nào đó.
Việc định nghĩa đơn giản hơn
khơng thể debug tìm lỗi của macro
trong thời gian thực thi. <sup>Debug đơn giản, dễ bắt lỗi</sup>Macro không cần quan tâm kiểu dữ
liệu của tham số và kiểu trả về. Như ví dụ trên, chúng ta có thể truyền kiểu int,float.
Phải chỉ rõ kiểu dữ liệu của tham số và giá trị trả về
Macro tạo ra các inline code, thời gian xử lí inline code ngắn hơn thời gian gọihàm
Chương trình mất thời gian dịch từ vùng nhớ hàm được lưu trữ sang vùng nhớ goi hàm.
Giả sử macro được gọi 20 lần trong chương trình, 20 dịng code sẽ được chèn vào chương trình trong q trình tiền xử lí. Điều này làm cho kích thướccủa chương trình (.EXE, .DLL, .LIB,…) phình to ra.
Giả sử 1 hàm được gọi 20 lần, sẽ chỉ có1 bản copy của hàm trong chương trình. Kích thước chương trình nhỏ hơnsử dụng macro.
Hàm inline là một hàm bình thường được định nghĩa bởi từ khoá <b>inline. </b>Hàm nội tuyến (inline) là một hàm ngắn được mở rộng bởi trình biên dịch. Và các đối sốcủa nó chỉ được đánh giá một lần. Hàm nội tuyến là các hàm có độ dài ngắn được tự động tạo thành các hàm nội tuyến mà khơng cần sử dụng từ khố nội tuyến bên trong lớp.
Cú pháp một hàm inline:
Inline return_type function_name (tham số){
//mã hàm nội tuyến}
Ví dụ:
</div><span class="text_page_counter">Trang 7</span><div class="page_container" data-page="7"><b>Đầu ra: </b>
Max (100, 1000): 1000Max (20, 0): 20
Trong khi macro không thể truy cập các thành viên dữ liệu của lớp.
Trong trường hợp hàm nội tuyến,
chương trình có thể dễ dàng gỡ lỗi. <sup>Trong khi trong trường hợp macro, </sup>chương trình khơng thể dễ dàng gỡ lỗi.Trong trường hợp nội dòng, các đối số
chỉ được đánh giá một lần. <sup>Trong khi trong trường hợp macro, các </sup>đối số được đánh giá mọi lúc bất cứ khinào macro được sử dụng trong chương trình.
Trong C ++, nội tuyến có thể được định nghĩa bên trong lớp hoặc bên ngoài lớp.
Trong khi macro là tất cả thời gian được xác định ở đầu chương trình.Trong C ++, bên trong lớp, các hàm có
độ dài ngắn sẽ tự động trở thành các hàm nội tuyến.
Macro được xác định cụ thể.Inline không được sử dụng rộng rãi
như macro. <sup>Macro được sử dụng rộng rãi.</sup>Inline khơng được sử dụng trong lập
trình cạnh tranh. <sup>Macro được sử dụng rất nhiều trong </sup>lập trình cạnh tranh.Hàm inline được kết thúc bằng dấu
ngoặc nhọn ở cuối
Trong khi macro không được kết thúc bằng bất kỳ ký hiệu nào, nó được kết thúc bằng một dòng mới.
</div><span class="text_page_counter">Trang 8</span><div class="page_container" data-page="8">Mỗi khi tạo ra một biến nào đó, trình biên dịch sẽ đưa ra 1 địa chỉ để lưu giữbiến đó. Khi chúng ta sử dụng biến có thể truy cập bằng tên biến hoặc con trỏ. Việccấp phát như vậy gọi là cấp phát tĩnh. Khi cấp phát tĩnh, ô nhớ đó sẽ tồn tại từ khi chương trình hoạt động tới khi chương trình kết thúc. Khi phải khai báo 1 mảng màchưa rõ phải sử dụng kích thước là bao nhiêu. Vậy thì nếu cấp phát tĩnh bộ nhớ chomảng đó sẽ xảy ra 2 vấn đề: Thiếu kích thước dẫn tới lưu thiếu bộ nhớ hoặc thừa kích thước dẫn tới lãng phí bộ nhớ Vậy nên chúng ta cần phải sử dụng cấp phát bộ nhớ động trong trường hợp này. Cấp phát động bộ nhớ chính là việc cấp phát/giải phóng, thay đổi kích thước bộ nhớ một cách linh hoạt. Giúp chúng ta điềukhiển được việc sử dụng bộ nhớ của chương trình.
Bộ nhớ được cấp phát trước khi chạy chương trình (trong quá trình biên dịch)
Bộ nhớ được cấp phát trong q trình chạy chương trình.
</div><span class="text_page_counter">Trang 9</span><div class="page_container" data-page="9">Khơng thể cấp phát hay phân bổ lại bộ nhớ trong khi chạy chương trình
Cho phép quản lý, phân bổ hay giải phóng bộ nhớ trong khi chạy chương trình
Vùng nhớ được cấp phát và tồn tại cho
đến khi kết thúc chương trình <sup>Vùng nhớ được cấp phát và tồn tại cho </sup>đến khi kết thúc chương trìnhChương trình chạy nhanh hơn so với
cấp phát động
Chương trình chạy chậm hơn so với cấp phát tĩnh
Tốn nhiều không gian bộ nhớ hơn Tốn nhiều không gian bộ nhớ hơn
Để cấp phát vùng nhớ động cho biến con trỏ trong ngôn ngữ C, bạn có thể sử dụng hàm malloc() hoặc hàm calloc(). Sử dụng hàm feee() để giải phóng bộ nhớ đãcấp phát khi không cần sử dụng, sử dụng realloc() để thay đổi (phân bổ lại) kích thước bộ nhớ đã cấp phát trong khi chạy chương trình.
Từ malloc là đại diện cho cụm từ memory allocation (dịch: cấp phát bộ nhớ).Hàm malloc() thực hiện cấp phát bộ nhớ bằng cách chỉ định số byte cần cấp phát. Hàm này trả về con trỏ kiểu void cho phép chúng ta có thể ép kiểu về bất cứ kiểu dữ liệu nào.
<b>Cú pháp của hàm malloc(): ptr = (castType*) malloc(size);</b>
Trong ví dụ trên, hàm calloc() thực hiện cấp phát 100 ô nhớ liêntiếp và mỗi ô nhớ có kích thước là số byte của kiểu int, như vậy ở ví dụ trên thì hàm cấp phát cho con trỏ kiểu int, với kích thước là 100*4 = 400byte, vì 1 int có kích thước là 4 byte. Hàm này cũng trả về con trỏ chứa giá trị là địa chỉ của byte đầu tiên trong khối bộ nhớ vừa cấp phát.Trong trường hợp không thể cấp phát bộ nhớ, nó sẽ trả về một con trỏ NULL.
</div><span class="text_page_counter">Trang 10</span><div class="page_container" data-page="10">Từ calloc đại diện cho cụm từ contiguous allocation (dịch: cấp phát liên tục).Hàm malloc() khi cấp phát bộ nhớ thì vùng nhớ cấp phát đó khơng được khởi tạo giá trị ban đầu. Trong khi đó, hàm calloc() thực hiện cấp phát bộ nhớ và khởi tạo tất cả các ơ nhớ có giá trị bằng 0. Vì thế nên hàm calloc sẽ cần thời gian thực thi lâu hợn malloc()
Hàm calloc() nhận vào 2 tham số là số ô nhớ muốn khởi tạo và kích thước của 1ơ nhớ.
<b>Cú pháp của hàm calloc(): ptr = (castType*)calloc(n, size); (với n là số lượng phần tử, size là kích thước mỗi phần tử)</b>
Hàm calloc được định nghĩa như sau: void* ICACHE_RAM_ATTR calloc(size_t count, size_t size)
Giá trị trả về là con trỏ void, tham số truyền vào là số lượng phần tử và kích thước của phần tử.
VD: <small>#include <stdio.h></small>
<small>#include <stdlib.h></small>
<small>int main(){ i nint, ; int *;</small>
<small> printf("Nhap so phan tu: \n"); scanf("%d",& );n a = ( *)intcalloc n,(sizeof int( )); printf("Nhap %d so: \n",n); for( =0 i i n i; < ; ++ ) {</small>
<small> scanf("%d",&a[i]); }</small>
<small> printf("Cac so vua nhap la: \n");</small>
</div><span class="text_page_counter">Trang 11</span><div class="page_container" data-page="11"><small> printf("%d ",a i[ ]); }</small>
<small> return( );0}</small>
Ta có kết quả chạy:
Việc cấp phát bộ nhớ động trong C dù sử dụng malloc() hay calloc() thì chúng cũng đều khơng thể tự giải phóng bộ nhớ. Bạn cần sử dụng hàm free() để giải phóng vùng nhớ.
<b>Cú pháp: free(ptr); // ptr là con trỏ</b>
Lệnh này sẽ giải phóng vùng nhớ mà con trỏ ptr đã được cấp phát. Giải phóng ởđây có nghĩa là trả lại vùng nhớ đó cho hệ điều hành và hệ điều hành có thể sử dụng vùng nhớ đó vào việc khác nếu cần. Nếu khơng giải phóng nó thì nó sẽ tồn tại cho tới khi chương trình kết thúc. Điều này sẽ rất nguy hiểm nếu chương trình liên tục cấp phát các vùng nhớ mới và sẽ gây ra hiện tượng tràn bộ nhớ.
Ví dụ sử dụng hàm malloc() và free()
<small>#include <stdio.h></small>
<small>// Thư viện này cần để cấp phát bộ nhớ động</small>
<small>#include <stdlib.h></small>
<small>intmain(){</small>
</div><span class="text_page_counter">Trang 12</span><div class="page_container" data-page="12"><small> // hàm malloc sẽ trả về con trỏ NULL</small>
<small> printf("Tong = %d",sum);</small>
<small> // Giải phóng vùng nhớ cho con trỏ</small>
<small> free(ptr);</small>
<small> return0;}</small>
</div><span class="text_page_counter">Trang 13</span><div class="page_container" data-page="13">Nếu việc cấp phát bộ nhớ động không đủ hoặc cần nhiều hơn mức đã cấp phát, bạn có thể thay đổi kích thước của bộ nhớ đã được cấp phát trước đó bằng cách sử dụng hàm realloc().
<b>Cú pháp của realloc(): ptr = realloc(ptr, n); </b>
Hàm này thực hiện cấp phát vùng nhớ mới cho con trỏ ptr. Vùng nhớ mới đó sẽ có kích thước mới là n bytes.
Hàm này cũng trả về con trỏ chứa giá trị là địa chỉ của byte đầu tiên trong vùng nhớ mới. Hàm này sẽ cố gắng mở rộng số ơ nhớ ra phía sau nếu có thể để giữ nguyên giá trị của con trỏ ban đầu. Trong trường hợp phải đổi sang một vùng nhớ khác, hàm realloc() cũng sẽ mang theo giá trị đã có ở vùng nhớ cũ sang vùng nhớ mới và giải phóng ln vùng nhớ cũ (đọc thêm tài liệu số 2). Trong trường hợp khơng thể, nó sẽ trả về con trỏ NULL giống như <b>malloc()</b> và <b>calloc().</b>
<b>Ví dụ: </b>
#include <stdio.h>#include <stdlib.h>
int main(){
int *ptr, i n1,n2;
printf("Nhap so luong phan tu: "); scanf("%d", &n1);
ptr=(int*)malloc(n1 *sizeof(int));
printf("Dia chi cua vung nho vua cap phat: %u",ptr);
printf("\nNhap lai so luong phan tu: "); scanf("%d", &n2);
// phân bổ lại vùng nhớ
ptr=(int*)realloc(ptr,n2 *sizeof(int));
</div><span class="text_page_counter">Trang 14</span><div class="page_container" data-page="14">printf("Dia chi cua vung nho duoc cap phat lai: %u",ptr); // giải phóng
free(ptr); return0;}
Kết quả chạy chương trình:
Việc sử dụng phương thức calloc sẽ an toàn hơn malloc trong lập trình vì vùng nhớ cấp phát động sẽ được gán giá trị bằng 0 thay vì giá trị rác như calloc. Tuy nhiên việc thêm 1 bước gán giá trị các ô nhớ bằng 0 này cũng sẽ khiến nó bị chậm hơn so với malloc do phải thực hiện thêm thao tác.
Sử dụng realloc và free một cách linh hoạt sẽ giúp các bạn điều khiển sự tăng giảm của bộ nhớ 1 cách dễ dàng
#include <conio.h>#include<stdio.h>
//C?ng hai ma tr?n
void AddMatrix(int *A,int *B,int*C,int M,int N) {
for(int I=0;I<M*N;++I) C[I] = A[I] + B[I]; }
//C?p phát vùng nh? cho ma tr?n
int AllocMatrix(int **A,int M,int N) // chú ý : ** {
*A = new int [M*N]; if (*A == NULL) return 0; return 1; }
//Gi?i phóng vùng nh? void FreeMatrix(int *A) {
if (A!=NULL) delete [] A; }
</div><span class="text_page_counter">Trang 16</span><div class="page_container" data-page="16">//Nh?p các giá tr? c?a ma tr?n
void InputMatrix(int *A,int M,int N,char Symbol) {
for(int I=0;I<M;++I) for(int J=0;J<N;++J){
printf("\n %c [%d][%d] = ", Symbol,I,J);scanf("%d",&A[I*N+J]);
//Hi?n th? ma tr?n
void DisplayMatrix(int *A,int M,int N) {
for(int I=0;I<M;++I) {
for(int J=0;J<N;++J) printf("%7d",A[I*N+J]); printf("\n");
} }
void NhanMT(int *A, int *B, int *D, int hang, int cot) {for (int i = 0; i < hang; i++) {
for (int j = 0; j < cot; j++) {D[i * cot + j] = 0;
for (int k = 0; k < cot; k++) {
</div><span class="text_page_counter">Trang 17</span><div class="page_container" data-page="17">D[i * cot + j] += A[i * cot + k] * B[k * cot + j];}
// void NhanMT (int *A, int *B, int *D, int M, int N){// for (int i=0 ; i< M; i++){
int M,N;
int *A = NULL,*B = NULL,*C = NULL, *D=NULL; printf("\n Nhap so dong cua ma tran: "); scanf("%d",&M); printf("\n Nhap so cot cua ma tran: "); scanf("%d",&N);//C?p phát vùng nh? cho ma tr?n A
if (!AllocMatrix(&A,M,N)) {
printf("\n Khong con du bo nho! ");
</div><span class="text_page_counter">Trang 18</span><div class="page_container" data-page="18">return 1; }
//C?p phát vùng nh? cho ma tr?n B if (!AllocMatrix(&B,M,N)) {
printf("\n Khong con du bo nho! "); FreeMatrix(A);//Gi?i phóng vùng nh? A return 1;
}
//C?p phát vùng nh? cho ma tr?n C if (!AllocMatrix(&C,M,N))
{
printf("\n Khong con du bo nho! "); FreeMatrix(A);//Gi?i phóng vùng nh? A FreeMatrix(B);//Gi?i phóng vùng nh? B return 1;
}
if (!AllocMatrix(&D,5,5)) {
printf("\n Khong con du bo nho! "); FreeMatrix(A);//Gi?i phóng vùng nh? A FreeMatrix(B);//Gi?i phóng vùng nh? B FreeMatrix(C);//Gi?i phóng vùng nh? C return 1;
}
</div><span class="text_page_counter">Trang 19</span><div class="page_container" data-page="19">printf("\n Nhap ma tran thu 1 "); InputMatrix(A,M,N,'A'); printf("\n Nhap ma tran thu 2 "); InputMatrix(B,M,N,'B'); printf("\n Ma tran thu 1\n"); DisplayMatrix(A,M,N); printf("\n Ma tran thu 2\n"); DisplayMatrix(B,M,N); AddMatrix(A,B,C,M,N); printf("\n Tong hai ma tran\n"); DisplayMatrix(C,M,N); NhanMT(A,B,D,M,N); printf("\nTich hai ma tran\n"); DisplayMatrix(D,M,N);
FreeMatrix(A);//Gi?i phóng vùng nh? A FreeMatrix(B);//Gi?i phóng vùng nh? B FreeMatrix(C);//Gi?i phóng vùng nh? C
FreeMatrix(D);//Gi?i phóng vùng nh? C return 0;
}
</div>