1. Trang chủ
  2. » Luận Văn - Báo Cáo

tìm hiểu về macro giới thiệu một sôố hàm cầốp phát bộ nhớ động trong c

19 0 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 19
Dung lượng 0,94 MB

Nội dung

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

Trang 1

Mục lục:

Phầần 1: Tìm hi u vềầ Macro trong ngôn ng l p trình C ể ữ ậ 2

I Macro 2

II Hàm(Function) 4

III Hàm inline (Inline function) 5

Phầần 2: Gi i thi u m t sôố hàm cầốp phát b nh đ ng trong ớ ệ ộ ộ ớ ộ C 8

I S d ng hàm malloc() ử ụ 9

II S d ng hàm calloc() ử ụ 9

III S d ng hàm free() ử ụ 11

IV S d ng hàm realloc() ử ụ 12

V L i kềốt: ờ 13

Phầần 3: Bài t p l p trình ậ ậ 14

Trang 2

Phần 1: Tìm hiểu về Macro trong ngôn ngữ lập trình C

I Macro

Macro được dùng để chỉ những hàm được viết ở phần Preprocessor (là các

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

Ví dụ:

Trang 3

// C program to illustrate macros

#include <stdio.h>

// Macro definition

#define LIMIT 5

// Driver Code

int main()

{

// Print the value of macro defined

printf("The value of LIMIT"

" is %d",

LIMIT);

return 0;

}

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

Ví dụ:

Trang 4

Chương trình chạy in ra: My name is: Alex

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

define USE_YEN

Các macro của biểu mẫu này hoạt động như sau: mọi sự xuất hiện tiếp theo của định danh macro này(USE_YEN) sẽ bị xóa và được thay thế bởi không có gì

Phạm vi định nghĩa của macro: Các chỉ thị sẽ được xử lý trước khi biên dịch,

từ trên xuống dưới của từng file Khi bộ tiền xử lý kết thúc, tất cả các định danh được định nghĩa từ file đó sẽ bị loại bỏ Điều này có nghĩa là các chỉ thị chỉ có giá trị từ điểm định nghĩa đến cuối file mà chúng được định nghĩa Các chỉ thị được định nghĩa trong một file code không có tác động đến các file code khác trong cùng một dự án

II Hàm(Function)

Hàm(Function) là 1 khối lệnh thực hiện một chức năng nào đó

Ví dụ: Hàm tìm giá trị lớn nhất của 1 số nguyên

Trang 5

Ta có kết quả đầu ra:

Ưu nhược điểm của Macro và Hàm:

Việc định nghĩa macro khó hơn định

nghĩa hàm

Nếu không chú ý, chúng ta dễ bị side

effect

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 Debug đơn giản, dễ bắt lỗi

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

hà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 quá trình

tiền xử lí Điều này làm cho kích thước

củ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ơn

sử dụng macro

III Hàm inline (Inline function)

Trang 6

Hàm inline là một hàm bình thường được định nghĩa bởi từ khoá inline 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ừ khoá 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ụ:

Trang 7

Đầu ra:

Max (100, 1000): 1000

Max (20, 0): 20

Sự khác nhau giữu Inline và Macro trong C++:

Một hàm nội tuyến được xác định bời

từ khoá inline

Trong khi các macro được xác định bời

từ khoá #define Thông qua chức năng nội tuyến, các

thành viên dữ liệu của lớp có thể được

truy cập

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 Trong khi trong trường hợp macro, 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 Trong khi trong trường hợp macro, các đối số được đánh giá mọi lúc bất cứ khi

nà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 Macro được sử dụng rộng rãi. Inline không được sử dụng trong lập

trình cạnh tranh Macro được sử dụng rất nhiều trong 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

Trang 8

Phần 2: Giới thiệu một số hàm cấp phát bộ nhớ động trong C

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ệc cấ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ớ cho mả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ều khiển được việc sử dụng bộ nhớ của chương trình

Sự giống và khác nhau của việc cấp phát động và cấp phát tĩnh Cấp phát bộ nhớ tĩnh Cấp phát bộ nhớ động

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 quá trình chạy chương trình

Trang 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 Vùng nhớ được cấp phát và tồn tại cho đến khi kết thúc chương trình

Chươ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

I Sử dụng hàm malloc()

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

Cú pháp của hàm malloc(): ptr = (castType*) malloc(size);

Trong ví dụ trên, hàm calloc() thực hiện cấp phát 100 ô nhớ liên

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

Trang 10

II Sử dụng hàm calloc()

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ớ

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

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:

#include <stdio.h>

#include <stdlib.h>

int main()

{

i n int , ;

int * ;

printf("Nhap so phan tu: \n");

scanf("%d",& ); n

a = ( *) int calloc n, ( sizeof int ( ));

printf("Nhap %d so: \n",n);

for ( =0 i i n i ; < ; ++ )

{

scanf( "%d" ,& a[i]);

}

printf("Cac so vua nhap la: \n");

Trang 11

printf("%d ",a i [ ]);

}

return ( ); 0

}

Ta có kết quả chạy:

III Sử dụng hàm free()

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ớ

Cú pháp: free(ptr); // ptr là con trỏ

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

0

1

2

3

4

5

6

7

8

9

1

#include <stdio.h>

// Thư viện này cần để cấp phát bộ nhớ động

#include <stdlib.h>

int main()

{

int n, i, * ptr, sum = 0 ;

printf( "Nhap so luong phan tu: " );

scanf( "%d" , &n);

ptr = ( int * )malloc(n * sizeof( int ));

Trang 12

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

2

7

2

8

2

9

3

0

3

// hàm malloc sẽ trả về con trỏ NULL

if (ptr == NULL )

{

printf( "Co loi! khong the cap phat bo nho." );

exit( 0 );

}

printf( "Nhap cac gia tri: " );

for (i = 0 ; i n; < ++ i)

{

scanf( "%d" , ptr + i);

sum += * (ptr + i);

}

printf( "Tong = %d" , sum);

// Giải phóng vùng nhớ cho con trỏ

free(ptr);

return 0 ;

}

Trang 13

IV Sử dụng hàm realloc()

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

Cú pháp của realloc(): ptr = realloc(ptr, n);

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 luôn 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ư malloc()calloc().

Ví dụ:

0

1

2

3

4

5

6

7

8

9

1

0

1

1

1

#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));

Trang 14

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

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:

V Lời kết:

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

Phần 3: Bài tập lập trình

Trang 15

Bài 1: Sử dụng mảng cấp phát động để thực hiện phép nhân ma trận

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

}

Trang 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++) {

Trang 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++){

// for(int j=0; j < N;j++){

// for (int k =0; k < N; i++){

// D[i*N+j]+= A[i*N+k] * B[k*N+j];

int main()

{

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! ");

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

}

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

}

Ngày đăng: 11/06/2024, 17:41

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w