22
EE3490: Kỹ thuật lập trình HK1 2018/2019 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội Bài 5: Hàm và thư viện 1

Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Bài 5: Hàm và thư viện

1

Page 2: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Hàm

(functions)

2

Page 3: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Khái niệm

Hàm là một khối các câu lệnh thực hiện một nhiệm vụ

nhất định, và có thể được gọi khi cần

Mỗi hàm có một tên (các hàm trong C không được trùng

tên nhau), một số tham số, và một giá trị trả về

Sử dụng hàm giúp:

Chia nhỏ chương trình thành nhiều bài toán con

Sử dụng lại trong một hoặc nhiều chương trình

Cách khai báo:

<kiểu trả về> <tên hàm>(<danh sách các tham số>) {

Khai báo các biến dùng cho hàm

Các câu lệnh của hàm

}

Câu lệnh return dùng để thoát khỏi hàm và trả kết quả3

Page 4: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Ví dụ

Hàm tính tổng hai số double sum(double x, double y) {

double z = x+y;

return z;

}

int main() {

double x = 10, y = sum(2,3);

printf("x + y = %g", sum(x,y));

return 0;

}

Các tham số và các biến nội bộ chỉ giới hạn trong phạm

vi của hàm

4

Page 5: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Phạm vi của biến, hằng

Biến toàn cục: được khai báo ở ngoài các hàm, có phạm vi trong

toàn chương trình và tồn tại trong suốt quá trình chạy

Biến địa phương: được khai báo ở trong một hàm hoặc một khối

lệnh, chỉ có phạm vi trong hàm/khối đó, và bị huỷ sau khi kết thúc

chạy hàm/khối đó

Khai báo biến địa phương sẽ “che” mất biến cùng tên khác có phạm vi rộng hơn

Trong C, biến địa phương phải được khai báo ở đầu hàm hoặc khối lệnh

Ví dụ biến địa phương của hàm: int x = 10, y = 20; /* phải khai báo trước hàm sum() */

int sum() {

int z = x+y;

return z;

}

int main() {

int x = 1, y = 2;

int z = sum(); /* trả về: 10+20 */

return 0;

}

5

Page 6: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Biến trong khối lệnh

Trong một khối lệnh { … } ta có thể khai thêm biến, biến đó chỉ tồn tại

từ khi chương trình chạy vào tới khi thoát khỏi khối lệnh đó

Ví dụ: int x = 1, y = 2;

int sum(int x, int y) {

return x+y;

}

int a = 1000, b = 2000;

int main() {

int x = 10, y = 20;

{

int x = 100, y = 200;

x+y;

}

x+y;

sum(a,b);

return 0;

}

6

Page 7: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Biến trong khối lệnh: vòng lặp

Chỉ có phạm vi trong một lần chạy của vòng lặp, mỗi

lần lặp sẽ tạo ra biến mới và khởi tạo lại

Ví dụ:

int x = 20;

for (i=0; i<10; i++) {

int y = 20;

x++; y++;

printf("%d %d\n", x, y);

}

7

Page 8: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Biến static

Là biến chỉ có phạm vi địa phương nhưng vẫn tồn tại ngay cả khi

chưa vào hoặc đã thoát khỏi hàm/khối

Khai báo bằng cách thêm từ khoá static int callCount() {

static int count = 0;

count++;

return count;

}

Cũng có biến static toàn cục: thuộc nội bộ của một file nguồn static int tic_time = 0;

void tic() {

tic_time = clock();

}

int toc() {

return clock() - tic_time;

}

Hàm static: tự tìm hiểu thêm

8

Page 9: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Câu lệnh return

Kết thúc hàm và trả về một giá trị cho nơi gọi nó int find(int number, int a[], int n) {

int i;

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

if (number == a[i])

return i;

return -1;

}

Hàm void: không trả về giá trị gì void copy(int *a, int *b, int n) {

if (a==NULL || b==NULL || a==b || n==0)

return;

for (; n>0; n--)

*a++ = *b++;

}

Câu lệnh return không có tham số

Không cần lệnh return ở cuối hàm

9

Page 10: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Tham số kiểu giá trị và kiểu tham chiếu

Tham số của hàm là biến tạm thời, tạo ra khi gọi và huỷ khi hàm kết

thúc gán giá trị cho tham số không ảnh hưởng tới biến nơi gọi void assign10(int x) { x = 10; }

int main() {

int a = 20;

assign10(a);

printf("a = %d", a);

return 0;

}

Dùng con trỏ nếu muốn thay đổi giá trị của biến ở nơi gọi void assign10(int *x)

{ *x = 10; }

int a = 20;

assign10(&a);

Tham số con trỏ thường được dùng như một cách khác để trả vềthêm giá trị, vì mỗi hàm chỉ có một giá trị trả về theo đúng nghĩa

10

x (int)

a

copy

a

x (int*)

&a

copy

Page 11: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Hàm trả về con trỏ

Vấn đề với hàm trả về biến địa phương int* sum(int x, int y) {

int z = x+y;

return &z;

}

int* p = sum(2, 3); /* sai */

Cấp phát bộ nhớ trong hàm int* sum(int x, int y) {

int* z = (int*)malloc(sizeof(int));

*z = x+y;

return z;

}

int* p = sum(2, 3);

/* ... */

free(p);

11

p

zint* sum() { }

copy*z

p

zint* sum() { }copy

địa chỉ

Page 12: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Nguyên mẫu (prototype) của hàm

Là việc khai báo hàm trước, nội dung của nó được triển

khai sau thường khai báo ở đầu file hoặc trong file .h

Ví dụ: double tong(double x, double y);

double tich(double x, double y);

int main() {

double x = 5., y = 10.;

tong(x, y);

tich(x, y);

return 0;

}

double tong(double x, double y) { return x+y; }

double tich(double x, double y) { return x*y; }

12

Page 13: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Hàm đệ quy (recursive function)

Là hàm có câu lệnh gọi chính nó

Ví dụ 1: giai thừa một số n unsigned int giai_thua(unsigned int n) {

if (n <= 1) return 1;

return n * giai_thua(n-1);

}

Ví dụ 2: x mũ n double mu(double x, unsigned int n) {

double y;

if (n == 0) return 1;

y = mu(x, n/2);

if (n%2 == 0) return y*y;

return y*y*x;

}

Không hiệu quả nếu sinh quá nhiều lệnh gọi hạn chế13

Page 14: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Con trỏ hàm

Là con trỏ trỏ tới một hàm là một kiểu dữ liệu trong C, thường

được dùng để gọi một hàm chưa biết trước double (*SomeOpt)(double, double);

typedef double (*OptFunc)(double, double);

OptFunc SomeOpt;

Ví dụ: double sum(double x, double y) { return x+y; }

double prod(double x, double y) { return x*y; }

int main() {

double (*SomeOpt)(double, double) = &sum;

SomeOpt(2., 5.); /* sum(2., 5.); */

SomeOpt = prod;

(*SomeOpt)(2., 5.); /* prod(2., 5.); */

return 0;

}

Phép gán có thể dùng & hoặc không, gọi cũng có thể dùng * hoặc

không

14

Page 15: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Macro

Macro là đoạn mã được đại diện bằng một tên, mà mỗi khi tên đó

xuất hiện trong chương trình thì sẽ được thay thế bằng đoạn mã

tương ứng #define ERROR { printf("Error, exit now!"); exit(-1); }

int main(int argc, char* argv[]) {

if (argc != 3) ERROR

/* … */

return 0;

}

Macro có thể được thay thế khi định nghĩa macro khác cùng tên Huỷ bỏ macro đã định nghĩa: #undef ERROR

Kiểm tra xem macro đã định nghĩa chưa #ifdef ERROR

/* ... */

#else

/* ... */

#endif

15

Page 16: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Macro (tiếp)

Macro có thể có tham số đôi khi được dùng như hàm #define MIN(x,y) x<y ? x:y

z = MIN(2,4); /* z = 2<4 ? 2:4; */

#define PI 3.1415

#define AREA(R) R*R*PI

z = AREA(5); /* z = 5*5*3.1415; */

Chú ý các hiệu ứng phụ #define MUL(x,y) x*y

z = MUL(2,4); /* z = 2*4; */

z = MUL(2+1,4); /* z = 2+1*4; */

z = 8/MUL(1+1,2); /* z = 8/1+1*2; */

#define MUL(x,y) ((x)*(y))

z = MUL(2+1,4); /* z = ((2+1)*(4)); */

z = 8/MUL(1+1,2); /* z = 8/((1+1)*(2)); */

#define SQR(x) ((x)*(x))

z = SQR(i); /* z = ((i)*(i)); */

z = SQR(i++); /* z = ((i++)*(i++)); */

16

Page 17: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Thư viện hàm

(libraries)

17

Page 18: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Thư viện hàm

Một chương trình có thể được chia nhỏ làm nhiều file, mỗi file chứa

một nhóm những hàm liên quan tới một phần của chương trình

Một số hàm có thể được dùng trong nhiều chương trình khác nhau

thư viện hàm

Một thư viện hàm gồm 2 phần:

File header có đuôi .h chứa prototype các hàm có thể dùng được của thư

viện

File mã nguồn có đuôi .c chứa nội dung các hàm, hoặc file .obj, .lib nếu

đã được dịch ra các dạng tương ứng

Dùng thư viện hàm trong một file mã nguồn:

#include <ten_file.h> /* trong đường dẫn mặc định */

#include "ten_file.h" /* cùng thư mục với file dịch */

Dẫn hướng #include có tác dụng như chèn nội dung file được khai báo

vào file đang dịch ở vị trí xuất hiện

18

Page 19: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Lưu ý với tạo và sử dụng file .h

Trong file abcd.h

Để tránh lỗi khi bị #include nhiều lần, thêm vào đầu và cuối

#pragma once

#ifndef __ABCD_H__

#define __ABCD_H__

/* Nội dung file abcd.h */

#endif

Các biến toàn cục phải được khai báo trong file .c, nếu muốn

được export thì trong file .h khai báo thêm bằng extern:

extern int bien_toan_cuc;

Sử dụng file abcd.h #include "abcd.h" /* .h cùng thư mục */

#include <abcd.h> /* .h trong thư mục thư viện */

19

Page 20: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Ví dụ: Thư viện tính diện tích các hình

dientich.h #ifndef __DIENTICH_H__

#define __DIENTICH_H__

extern const double PI;

double dt_tron(double r);

double dt_elip(double r1, double r2);

double dt_vuong(double l);

double dt_chu_nhat(double l1, double l2);

#endif

dientich.c const double PI = 3.1415;

double dt_tron(double r)

{ return r*r*PI; }

double dt_elip(double r1, double r2)

{ return r1*r2*PI; }

double dt_vuong(double l)

{ return l*l; }

double dt_chu_nhat(double l1, double l2)

{ return l1*l2; }20

Page 21: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Một số thư viện chuẩn

Tên Chức năng

stdio.h Xuất, nhập với màn hình, file, bàn phím,…

ctype.h Kiểm tra các lớp ký tự (chữ số, chữ cái,…)

string.h Xử lý chuỗi và bộ nhớ

memory.h Cấp phát và quản lý bộ nhớ động

math.h Một số hàm toán học

stdlib.h Chuyển đổi dữ liệu số-chuỗi, cấp phát bộ

nhớ,…

time.h Các hàm về thời gian

21

Page 22: Bài 5: Hàm và thưviện. C - Functions and... · Ví dụ 1: giai thừa một số n ... một nhóm những hàm liên quan tới một phần của chương trình Một số

EE3490: Kỹ thuật lập trình – HK1 2018/2019

TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội

Bài tập

1. Viết hàm cấp phát bộ nhớ và nhập giá trị cho một mảng, trả về con

trỏ mảng và số phần tử

2. Viết hàm prime(…) trả về mảng các số nguyên tố bé hơn n

3. Định nghĩa mảng các struct MenuItem { Tiêu đề, Hàm xử lý }, in ra

màn hình menu, nhận lựa chọn của người dùng và thực hiện chức

năng tương ứng

4. Viết hàm tính số Fibonacci thứ n được định nghĩa:

Fib0 = 0, Fib1 = 1

Fibn = Fibn-1 + Fibn-2 (n ≥ 2)

5. Định nghĩa kiểu chuỗi String và viết thư viện một số hàm xử lý

chuỗi: khởi tạo, copy, nối, tìm kiếm,…

6. Định nghĩa kiểu struct Shape rồi viết thư viện có hàm tính diện

tích, chu vi của hình tuỳ theo dạng của nó. Dùng 2 cách: switch và

con trỏ hàm

22