1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Bài giảng Lập trình nâng cao

201 7 0

Đ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 201
Dung lượng 2,65 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Cấu chúc chung của hàmcần viết tên tham số ▪ Vẫn phải viết kiểu trả về và tên hàm.. Quy tắc▪ Mô tả đủ thông tin để có thể phát lời gọi hàm ▪ Phải viết trước bất kỳ lời gọi hàm nào ▪ Phải

Trang 1

LẬP TRÌNH NÂNG CAO

Bài 1: Giới thiệu môn học và nhắc lại

kiến thức C/C++

Trang 2

Nội dung chính

Trang 3

Giới thiệu môn học

Phần 1

Trang 4

Giáo trình & Giờ học

▪ Visual Studio Code

Trang 5

Nội dung giảng dạy

3 Xâu ký tự và các phép toán trên xâu

Trang 6

Nội dung giảng dạy

Trang 7

Nội dung giảng dạy

Trang 8

Mục tiêu của môn học

niệm nền tảng của lập trình

Trang 9

Tại sao phải học môn này?

các môn lập trình khác

Trang 10

Thi & Tính điểm

▪ Điểm quá trình (50%):

• Điểm chuyên cần

• Điểm kiểm tra giữa kỳ (2 đầu điểm)

▪ Điểm kiểm tra cuối kì (50%, thi thực hành, máy chấm tự động)

thực hành trên máy, chú trọng vào viết chương trình,

không có lý thuyết học thuộc

truongxuannam@gmail.com

Trang 11

Một vài chú ý khác

hành)

https://txnam.net mục BÀI GIẢNG

ghi chép nhiều trong giờ lý thuyết

Trang 12

Nhắc lại kiến thức C/C++

Phần 2

Trang 13

Ôn luyện kiến thức C/C++

▪ Biến

▪ Phép toán (+, -, *, /, %, &, |, ^, !, &&, ||, ~, <<, >>, )

Trang 14

Ôn luyện kiến thức C/C++

Trang 15

Ôn luyện kiến thức C/C++

Trang 16

Ôn lại kiến thức

Trang 17

Bài tập

Phần 3

Trang 18

Bài tập

Trang 19

LẬP TRÌNH NÂNG CAO

Bài 2+3: Hàm trong C/C++

Trang 20

Nội dung chính

8 Bài tập

Trang 21

Cấu chúc chung của hàm

Phần 1

Trang 22

Cấu chúc chung của hàm

▪ Thông qua tên

Trang 23

Cấu chúc chung của hàm

của file hoặc tách riêng thành một file (gọi là file header)

Trang 24

Cấu chúc chung của hàm

cần viết tên tham số

▪ Vẫn phải viết kiểu trả về và tên hàm Riêng phần tham

số chỉ cần viết kiểu và bỏ qua phần tên

Trang 25

Cấu chúc chung của hàm

cần viết tên tham số

trên viết một đằng ở dưới viết một nẻo vẫn được chấp nhận

Trang 26

Cấu trúc của một chương trình C/C++

Trang 27

Quy tắc

▪ Mô tả đủ thông tin để có thể phát lời gọi hàm

▪ Phải viết trước bất kỳ lời gọi hàm nào

▪ Phải có kiểu trả về của hàm

▪ Phải có kiểu của từng tham số

▪ Không nhất thiết phải có tên tham số

▪ double mu_x (int, double);

▪ double mu_x (int a, double d);

▪ d = mu_x (3, 0.5);

▪ Những giá trị thực sự được dùng trong lời gọi hàm được gọi là đối số (argument) hoặc tham số thực (actual parameter)

Trang 28

▪ Còn gọi là các tham số hình thức (formal parameter)

▪ Trả về kết quả thông qua lệnh return

màn hình), thì khai báo kiểu void và không cần return nữa

▪ double mu_x (int a, double d) {

double k = 1 ;

k *= d;

return k }

Trang 29

Thảo luận

▪ Tái sử dụng : Mã được viết một lần, sử dụng nhiều lần

▪ Giảm chi phí : Sửa lỗi, nâng cấp ở một đoạn mã

▪ Dễ phát triển : Chia chương trình phức tạp thành nhiều đơn

thể, giảm độ phức tạp khi viết các khối mã

▪ Phát triển song song

(functional abstraction)

Trang 30

Hiểu về cách hàm hoạt động

Phần 2

Trang 32

Các hàm có sẵn

Phần 3

Trang 33

Các hàm có sẵn

cấp cho chúng ta sử dụng

▪ Thư viện thường gồm 2 loại file:

• File header: chỉ chứa các khai báo hàm (.h, hpp hoặc không đuôi)

• File source: chứa phần thân hàm (.c, cpp)

▪ Khai báo thư viện thông qua phát biểu #include

▪ Phát biểu #include phải chỉ ra file header sẽ sử dụng

▪ #include <iostream> ← tìm file trong thư mục chuẩn

▪ #include "mylib" ← tìm file trong thư mục hiện tại

Trang 34

Các hàm có sẵn

Trang 35

Các hàm có sẵn

Trang 36

Tạo số ngẫu nhiên

▪ Tạo các tình huống ngẫu nhiên trong chương trình, trò chơi

▪ Tạo các biến ngẫu nhiên trong tính toán khoa học

▪ Chỉ là giả-ngẫu-nhiên

▪ rand () : trả về giá trị nguyên giữa 0 & RAND_MAX

• RAND_MAX tùy thuộc vào từng thư viện và trình biên dịch

• Trả về số ngẫu nhiên giữa 0 & 5

• Trả về số ngẫu nhiên giữa k & 5+k

▪ Khởi tạo nhân cho việc tạo số ngẫu nhiên: srand ( time ( 0 ))

Trang 37

Phạm vi của biến và của hàm

Phần 4

Trang 38

Quy tắc

nào) thì chỉ được truy cập bên trong khối đó

▪ Biến không nằm trong bất kỳ cặp ngoặc nào: biến toàn cục

(global variable)

▪ Biến nằm trong hàm: biến cục bộ (local variable)

▪ Có thể truy cập từ bất kỳ đâu trong chương trình

▪ Chú ý: một chương trình có thể gồm nhiều file

▪ Có thể truy cập biến ở trong file khác: từ khóa extern

▪ Rất cẩn thận khi sử dụng

Trang 39

Từ khóa static

biến cục bộ

trong phạm vi của file hiện tại

truy cập trong phạm vi của file hiện tại

không bị hủy đi khi kết thúc hàm

▪ Chỉ khởi tạo một lần

▪ Hàm lần sau sử dụng giá trị còn tồn lại từ lần gọi trước

Trang 40

// hàm module, chỉ gọi được từ đoạn mã cùng file

static void dosmt ( bool a ) {

bool b = true ; // biến cục bộ, phạm vị hàm

// hàm toàn cục, định nghĩa hàm được viết ở file khấc

extern int somefuction ( int n );

Trang 41

Ví dụ về biến static, hãy chạy thử xem nào!

Trang 42

Truyền tham số trong hàm

Phần 5

Trang 43

③Khai báo biến k = 1

⑤Trả về kết quả qua lệnh

return và thoát khỏi hàm

Vấn đề: Biến a và d là biến của hàm, việc thay đổi giá trị chỉ có tác dụng nội bộ

Trang 45

Cách giải quyết: tham chiếu (&)

▪ Alias (nickname) của một biến khác

▪ Khai báo như biến, nhưng thêm dấu & vào trước tên biến

Trang 46

Ví dụ viết lại bằng tham chiếu

Trang 47

Tham chiếu có ưu điểm và có điểm bất tiện

tham chiếu luôn có kích thước 4 byte – tùy OS)

biến, không làm việc với

dữ liệu trực trị (giá trị viết trực tiếp vào đối số)

biến cục bộ có thể gây những lỗi bộ nhớ

Trang 48

Quy tắc chung

▪ Muốn thay đổi giá trị đối số thì hãy sử dụng tham chiếu (thêm dấu & vào trước tên biến)

thể sử dụng tham chiếu

▪ Muốn ngăn chặn việc vô ý thay đổi dữ liệu tham chiếu thì thêm

từ khóa const vào trước tham chiếu

// dùng khi cần thay đổi d

int change (string & d )

// dùng khi cần hàm nhanh hơn

int change (string & d )

// dùng khi cần hàm nhanh hơn và không thay đổi d

int change ( const string & d )

Trang 49

Nạp chồng hàm

Phần 6

Trang 50

Khái niệm

nhiều hàm cùng tên nhau trong một chương trình

trung bình cộng của 2, 3 hoặc 4 số thực

double trungbinh ( double a , double b ) {

Trang 51

Khái niệm

trungbinh2, trungbinh3 và trungbinh4

▪ Làm mất ý nghĩa của tên hàm: trungbinh2 có thể hiểu là trung bình bình phương ?

hàm hợp lý nhất trong số các hàm trùng tên

▪ Dựa trên kiểu dữ liệu của các tham số của hàm

▪ Không dựa trên kết quả trả về của hàm

▪ Cơ chế này gọi là tự động phân giải nạp chồng (automatic

overload resolution)

Trang 52

Nạp chồng hàm: tình huống đơn giản

#include <iostream>

using namespace std;

void print ( int a , int b ) { cout << "0" << endl; }

void print ( int a , double b ) { cout << "1" << endl; }

void print ( double a , int b ) { cout << "2" << endl; }

int main () {

print ( 10 , 20 ); // print(int, int)

print ( 0.5 , 100 ); // print(double, int)

print ( 5 , 0.5 ); // print(int, double)

print ( 1.5 , 0.5 ); // Lỗi

}

Trang 53

Nạp chồng hàm: tình huống chuyển đổi kiểu

#include <iostream>

using namespace std;

void print ( long a , long b ) { cout << "0" << endl; }

void print ( long a , double b ) { cout << "1" << endl; }

void print ( double a , long b ) { cout << "2" << endl; }

void print ( double a , double b ) { cout << "3" << endl; }

int main () {

print ( 10 , 20 ); // Lỗi

print ( 0.5 , 100L ); // print(double, long)

print ( 5L , 0.5 ); // print(long, double)

print ( 1.5 , 0.5 ); // print(double, double)

}

Trang 54

Nạp chồng hàm: tham số mặc định

#include <iostream>

using namespace std;

double area ( double dai , double rong = 1 ) {

return dai * rong;

}

int main () {

cout << area ( 10 , 20 ) << endl; // dai = 10, rong = 20

cout << area ( 10 ) << endl; // dai = 10, rong = 1

}

Trang 55

Nạp chồng hàm giúp thiết kế linh hoạt hơn

Trang 56

Hàm đệ quy

Phần 7

Trang 57

Khái niệm đệ quy

▪ Đệ quy trực tiếp: gọi lại chính nó ngay trong thân hàm

▪ Đệ quy gián tiếp: gọi lại chính nó thực hiện trong các hàm con

phổ biến trong toán học, tin học, vật lý,

▪ Giải bài toán với trường hợp nhỏ nhất

▪ Giải bài toán lớn dựa trên lời giải từ bài toán con

Trang 59

Hàm đệ quy thực hiện như thế nào?

Trang 60

Hàm đệ quy thực hiện như thế nào?

Trang 61

Bài tập

Phần 8

Trang 62

Bài tập

Trang 63

Bài tập

Trang 64

Bài tập

𝐶𝑛𝑘

Trang 65

LẬP TRÌNH NÂNG CAO

Bài 4+5+6 : Kiểu dữ liệu mảng và xâu ký

tự trong C/C++

Trang 66

2 Các phép toán trên xâu kí tự

3 Các bài toán cơ bản với kiểu xâu kí tự

4 Xâu kí tự vs Chuỗi (string)

Trang 67

Kiểu dữ liệu mảng

Phần 1

Trang 68

1.1 Khái niệm và khai báo

▪ Chỉ số là số tự nhiên, luôn bắt đầu từ 0

▪ Là giải pháp cho phép lưu trữ một dãy các biến tương đương, thay vì phải chỉ ra từng biến một

Trang 69

1.1 Khái niệm và khai báo

▪ Kích cỡ (số phần tử) được xác định ngay khi khai báo (thường phải là hằng số)*

▪ Kích cỡ không thể thay đổi

▪ Sẽ là một khối nhớ liên tục chứa các biến

Trang 70

1.1 Khái niệm và khai báo: một số lỗi hay gặp

▪ int a[]; => int a[ 100 ];

▪ int n1 = 10 ; int a[n1]; => int a[ 10 ];

▪ const int n2 = 10 ; int a[n2]; => int a[ 10 ];

Trang 71

// mảng số nguyên hai chiều 3 hàng x 4 cột

// chú ý cách khởi tạo dữ liệu

int mang22 [ 3 ][ 4 ] = {

{ 1 , 2 , 3 , 4 }, { 5 , 6 , 7 }, { 8 , 9 , 10 } };

Trang 72

1.2 Mảng nhiều chiều

biến nằm liên tiếp thành một khối trong bộ nhớ

int mang22 [ 3 ][ 4 ] = { 1 , 2 , 3 , 4 , 5 , 6 };

Trang 73

▪ Không an toàn khi sử dụng

trong hàm (thay đổi giá trị)

Trang 74

1.4 Hàm với tham số kiểu mảng

#include <iostream>

#include <vector>

using namespace std;

typedef int Mang [ 100 ]; // định nghĩa kiểu mảng

void change (Mang x ) {

Trang 75

1.5 Vòng lặp phạm vi

mới bằng option sau: menu => Tools => Compiler Options

“-static-libgcc -std=c++11”

Trang 76

1.5 Vòng lặp phạm vi

for ( auto & x : mang21) {

for ( auto & y : x) cout << y << " ";

cout << endl;

}

Trang 77

1.6 Các bài toán cơ bản với kiểu mảng

▪ Danh sách điểm số, sinh viên, => mảng 1 chiều

▪ Âm thanh số hóa => mảng 1 chiều

▪ Hình ảnh số hóa => mảng 2 chiều

▪ Dữ liệu tài nguyên, đất đai, không gian, => mảng 3 chiều

Trang 78

1.6 Các bài toán cơ bản với kiểu mảng

các vấn đề cơ bản

▪ sort : sắp xếp một dãy

▪ find : tìm kiếm trong dãy

▪ binary_search : kiểm tra xem có phần tử trong đoạn tăng dần hay không

▪ lower_bound : trả về vị trí của phần tử đầu tiên không bé hơn phần tử cần tìm

▪ upper_bound : trả về vị trí của phần tử đầu tiên lớn hơn phần

tử cần tìm

Trang 79

Kiểu xâu kí tự

Phần 2

Trang 80

2.1 Khái niệm và khai báo

▪ 1 byte, char (- 128 127) hoặc unsigned char (0 255)

▪ Kiểu dữ liệu số nguyên

▪ Viết trong cặp ngoặc đơn: 'a' 'x' '&’

▪ Hoặc viết giá trị mã của chữ

▪ Tức là hai cách viết dưới đây hoàn toàn như nhau:

Trang 81

2.1 Khái niệm và khai báo

Trang 82

2.1 Khái niệm và khai báo

char str [ 4 ] = "C++";

char str[] = {'C','+','+',' \0 '};

char str [ 4 ] = {'C','+','+',' \0 ’ };

dùng để biểu diễn kích cỡ khi làm việc với bộ nhớ và kích

cỡ các biến

▪ X có thể là một biểu thức

Trang 83

2.2 Các phép toán trên xâu kí tự

▪ Thư viện <cstring> (string.h): nhiều hàm kiểu xâu kí tự

Trang 84

2.3 Các bài toán cơ bản với kiểu xâu kí tự

Trang 85

▪ Kiểu dữ liệu sẵn có của C/C++

▪ Không cần thư viện ngoài

▪ Hàm bổ trợ dùng con trỏ

▪ Không an toàn khi sử dụng

trong hàm (thay đổi giá trị)

▪ Phải gán giá trị từng phần tử

khi sao chép mảng

Chuỗi

▪ Kiểu dữ liệu của thư viện std

Xâu kí tự

Trang 86

Bài tập

Phần 3

Trang 87

Bài tập về mảng

Trang 89

Bài tập về xâu kí tự

Trang 90

LẬP TRÌNH NÂNG CAO

Bài 7+8+9 : Con trỏ và bộ nhớ trong

C/C++

Trang 92

Bộ nhớ máy tính

Phần 1

Trang 93

Các kiểu lưu trữ thông tin trên máy tính

Trang 94

▪ Một dãy các byte liên tiếp (một mảng byte khổng lồ)

▪ Có thể biết chính xác “địa chỉ” của chúng?

▪ Có thể “tóm” được chúng và đọc / ghi giá trị?

Trang 95

Bộ nhớ vật lý và bộ nhớ bảo vệ

Trang 96

Bộ nhớ của chương trình C/C++

Trang 97

Biến và địa chỉ của biến

Phần 2

Trang 98

Biến và địa chỉ của biến

nào đó, vị trí này gọi là địa chỉ (address) của biến

▪ Phép toán địa chỉ: &

▪ Trả về địa chỉ của biến

▪ Thường là một số 32 bit (tùy vào CPU, OS và kiểu chương trình)

int a[] = { 1 , 3 , 2 , 4 , 2 };

cout << &a << endl;

cout << & a [ 0 ] << endl;

cout << & a [ 1 ] << endl;

cout << ( long ) & a [ 2 ] << endl;

▪ Có lấy được địa chỉ của thứ khác trong bộ nhớ không?

Trang 99

Biến con trỏ

Phần 3

Trang 100

Biến con trỏ

▪ Có, sử dụng biến có kiểu “con trỏ”

int a = 10 ;

int *pa = &a; // con trỏ tới biến a

cout << "A = " << a << endl;

cout << "PA (con tro) = " << pa << endl;

cout << "PA (int) = " << ( int ) pa << endl;

int a, *b, c, **d;

Trang 101

Khai báo và khởi tạo con trỏ

int *p1; // con trỏ đến giá trị int

double *p2; // con trỏ đến giá trị thực

bool *p3; // con trỏ đến giá trị logic

int **p4; // con trỏ đến con trỏ kiểu nguyên

int n;

int *p1 = &n; // con trỏ đến n

double *p2; // con trỏ đến đâu???

bool *p3 = NULL ; // con trỏ NULL

▪ NULL là một giá trị đặc biệt, bằng 0 ( nullptr từ C++11)

Trang 102

Sử dụng con trỏ

con trỏ sẽ có tốc độ cao hơn do dễ dàng dịch thành các mã máy tương ứng (lý do ngôn ngữ lập trình C/C++ chạy nhanh)

▪ Biết địa chỉ của biến, biết biến đó nằm ở đâu trong bộ nhớ

▪ Thông qua con trỏ, có thể truy cập vào biến để đọc/ghi giá trị

Trang 103

Con trỏ làm tham số của hàm: có gì đặc biệt?

Trang 104

Quy tắc sử dụng con trỏ

qua khả năng hiểu và sử dụng con trỏ của ứng viên

▪ Hai phép toán đối lập: & và *

▪ Phép & trả về địa chỉ của biến

▪ Phép * trả về biến từ địa chỉ

▪ *pa và a đều chỉ nội dung của biến a

• *pa còn được gọi là truy cập gián tiếp vào a

▪ pa và &a đều là địa chỉ của biến a

Trang 105

Phép toán trên con trỏ

▪ Hai con trỏ bằng nhau, trỏ đến cùng một chỗ

Trang 106

Phép toán trên con trỏ

Trang 107

Phép toán trên con trỏ

▪ Đối ngẫu với phép cộng con trỏ với số nguyên

int *pa = &a, *pb = &b;

cout << pb-pa << endl;

short *ppa = ( short *) pa;

short *ppb = ( short *) pb;

cout << ppb-ppa << endl;

Trang 108

Phép toán trên con trỏ

Trang 109

Mảng và con trỏ

Phần 4

Trang 110

Mảng và con trỏ

điểm giống nhau về cách sử dụng, thậm chí sử dụng có phần lẫn lộn

▪ Vì lý do đó nên một số tài liệu xem mảng là hằng con trỏ (tức là một con trỏ nhưng trỏ đến một vị trí cố định trong bộ nhớ),

điều này không hoàn toàn chính xác

▪ Cách tốt nhất là hãy phân biệt rạch ròi giữa mảng và con trỏ, cho dù chúng có nhiều đặc điểm chung

int a [ 5 ], *p1, *p2;

p1 = a; // p trỏ đến đầu của a, tức a[0]

p2 = & a [ 0 ]; // p trỏ đến a[0]

cout << p1 << endl; // in ra địa chỉ của a

in ra địa chỉ của a[0], giống p1

Trang 111

Mảng và con trỏ

int a [ 5 ] = { 1 , 2 , 3 , 4 , 5 }, *p = a;

cout << a [ 2 ] << endl; // 3, bình thường

cout << *(a+ 2 ) << endl; // 3, dùng a như con trỏ

cout << *(p+ 2 ) << endl; // 3, bình thường

cout << p [ 2 ] << endl; // 3, dùng p như mảng

cout << *( 2 +p) << endl; // 3, lạ chưa?

int a [ 5 ], *p = a;

cout << sizeof (a) << endl; // 20

cout << sizeof (p) << endl; // 4

int * a [ 5 ];

int ** p ;

Trang 112

Mảng và con trỏ

chính nó:

▪ Bạn có lời giải thích nào không?

void print ( int a [], int n ) {

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

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

cout << *(a++) << " "; // lỗi

Trang 113

Bộ nhớ động

Phần 5

Trang 114

Bộ nhớ động

▪ Vùng code : chứa mã thực thi

▪ Vùng data (static memory):

chứa các dữ liệu được khởi

tạo từ ban đầu, thường là

các biến global

▪ Vùng stack : chứa các biến địa

phương

• Vùng này sẽ tăng giảm theo

độ sâu gọi hàm (call stack)

▪ Vùng heap : chứa các biến sẽ

được “cấp phát động”

• Chẳng hạn như dữ liệu của vector, có thể lúc ít phần tử, lúc khác lại chứa rất nhiều phần tử

Trang 115

Bộ nhớ động

động” – khi nào cần mới yêu cầu cấp

nào để hiển thị và soạn thảo một file?

▪ Không thể biết trước được, có những file rất ít dữ liệu, có

những file cực nhiều dữ liệu

động, xin bộ nhớ theo nhu cầu của phần mềm

▪ Một số tài liệu nói C cấp phát ở “heap” còn C++ cấp phát ở

“free store”, thực chất hai vùng nhớ này là một

Trang 116

Cấp phát động kiểu C: cấp theo khối nhớ

▪ Sử dụng thư viện: <stdlib.h>

▪ malloc (N) – cấp một khối nhớ cỡ N byte

▪ calloc (N, S) – cấp một khối nhớ cỡ N x S byte, điền số 0 vào mọi

ô dữ liệu được cấp phát

▪ free (p) – hủy khối nhớ được cấp cho con trỏ p

▪ realloc (p, S) – chỉnh kích cỡ khối nhớ được cấp bởi con trỏ p thành cỡ S byte, giữ lại dữ liệu cũ đã được khởi tạo

▪ Các hàm cấp phát trả về con trỏ void (void *)

▪ Cấp phát không thành công sẽ trả về con trỏ nullptr

Ngày đăng: 28/12/2021, 19:24

HÌNH ẢNH LIÊN QUAN

Sơ đồ bộ nhớ của struct A - Bài giảng Lập trình nâng cao
Sơ đồ b ộ nhớ của struct A (Trang 156)
Sơ đồ bộ nhớ của union Date - Bài giảng Lập trình nâng cao
Sơ đồ b ộ nhớ của union Date (Trang 159)