Professional Documents
Culture Documents
On Tap C++
On Tap C++
Nội dung
1. Biến
CẤU TRÚC DỮ LIỆU VÀ GIẢI 2. Hàm
THUẬT
3. Mảng
Data Structures & Algorithms
ÔN TẬP NHẬP MÔN LẬP TRÌNH 4. Cấu trúc
5. Con trỏ
1. Biến 1. Biến
- Biến là một ô nhớ hoặc 1 vùng nhớ dùng để chứa dữ liệu Cách khai báo:
trong quá trình thực hiện chương trình
type variableNames;
- Mỗi biến có một kiểu dữ liệu cụ thể, kích thước của biến − type: là một trong các kiểu dữ liệu hợp lệ.
phụ thuộc vào kiểu dữ liệu.
− variableNames: tên của một hay nhiều biến phân
- Giá trị của biến có thể được thay đổi, tất cả các bài phải cách nhau bởi dấu phẩy.
khởi tạo trước khi sử dụng
int so_nguyen; float mark1;
- Qui cách đặt tên biến: float so_thuc;
int x;
• Không trùng với các từ khóa, hoặc tên hàm.
• Ký tự đầu tiên là chữ cái hoặc _
• Không được sử dụng khoảng trắng ở giữa các ký tự
• Nên sử dụng tất cả chữ thường với dấu _ giữa các từ.
1
9/24/2018
•Mỗi 1 biến khi được khai báo sẽ được cấp 1 vùng nhớ với
Ngoài ra, ta có thể vừa khai báo vừa khởi tạo địa chỉ duy nhất để lưu trữ biến đó.
giá trị ban đầu cho biến:
•Để truy cập vào địa chỉ của một biến ta sử dụng câu lệnh.
type varName1=value, ... ,varName_n=value; &
Ví dụ:
float mark1, mark2, mark3, average = 0;
#include <iostream>
int main() 008FF82C
{ a 5
int a = 5;
std::cout<<"Gia tri cua a: "<<a<<'\n';
std::cout<<"Dia chi cua a: "<<&a<<'\n'; Gia tri cua a: 5
return 0; Dia chi cua a: 008FF82C
}
8
9 10
Ví dụ 1 Ví dụ 2
#include <iostream> #include <iostream> Kiểu dữ liệu Giá trị khởi tạo
int g; int g = 20;
int main() int main()
int 0
{ { char ‘\0’
int a = 2, b = 3; int a = 2, b = 3;
g = a + b; g = a + b; float 0
std::cout<<g; std::cout<<g;
return 0; return 0;
double 0
} } pointer NULL
11 12
g = ??? g = ???
2
9/24/2018
Cách định nghĩa hằng trong C++: Có 2 cách Cách định nghĩa hằng trong C++: Có 2 cách
Cách 1: Sử dụng #define
Cách 2: Sử dụng const
Câu lệnh:
#define tên_hằng giá_trị Lưu ý: Không có ký tự ; Câu lệnh:
Ví dụ:
Ví dụ: const kiểu_giá_trị tên_hằng = giá_trị_hằng;
#include <iostream>
int main()
#include <iostream>
{
#define PI 3.14
const int PI = 3.14;
int main()
int r = 2;
{
std::cout<<r*PI;
int r = 2;
getch();
std::cout<<2*r*PI;
return 0;
return 0;
}
}
6.28 6.28
13
Địa chỉ
ô nhớ • Toán tử & (Address-of Operator) đặt trước tên biến và
0
ch cho biết địa chỉ của vùng nhớ của biến.
1 x
2 • Toán tử * (Dereferencing Operator hay Indirection
3 a
int main() { Operator) đặt trước một địa chỉ và cho biết giá trị lưu trữ
4
char ch=‘x’; 5 7 tại địa chỉ đó.
int a = 7; 6
• Ví dụ:
} 7
. .
. .
. .
…
Memory Layout (bytes) 15
2. Hàm
int value; 0x50
value = 3200; value 3200 Hàm là một khối lệnh thực hiện một công việc hoàn
chỉnh (module), được đặt tên và được gọi thực thi nhiều
Memory Layout
lần tại nhiều vị trí trong chương trình.
cout << " value = " << value;
=> value = 3200; Hàm còn gọi là chương trình con (subroutine)
3
9/24/2018
2. Hàm 2. Hàm
• Parameter
• tạm dịch: Tham số hoặc tham số hình thức
• Là các thông số mà hàm nhận vào
• Xác định khi khai báo hàm
Gọi hàm
• Argument
• Tạm dịch: Đối số hoặc Tham số thực sự Truyền đối số
• Là các thông số được đưa vào hàm khi tiến hành gọi hàm
• Hai thuật ngữ này đôi khi dùng lẫn lộn và gọi chung
là Tham số
Tham số
22
2. Hàm Ví dụ
• Hàm có đầu ra, không có đầu vào:
• Tên hàm: nhap_so_duong , Hàm yêu cầu người dùng
Nội dung nhập vào một số nguyên dương. Nếu không phải số
Tên hàm Đầu vào Đầu ra
của hàm dương yêu cầu nhập lại.
• Chức năng • Số lượng • Kiểu dữ • Các lệnh • Đầu vào: Không có
của hàm tham số, liệu đầu ra cần thiết để • Đầu ra: số nguyên dương.
kiểu dữ liệu • Một số hàm hàm thực
• Một số hàm không có hiện công int nhap_so_duong(){
không có đầu ra việc int n;
đầu vào (void) do {
cout << "Nhap mot so nguyen duong";
cin >> n;
} while (n <= 0);
return n;
}
4
9/24/2018
Ví dụ Ví dụ
• Hàm có đầu vào, không có đầu ra: • Hàm không có đầu vào lẫn đầu ra
• Tên hàm: xuat_so_lon, Xuất ra màn hình số lớn hơn • Tên hàm: nhap_xuat_so_lon, Yêu cầu nhập
trong 02 số. vào 02 số nguyên và xuất ra màn hình ước
• Đầu vào: Hai số nguyên. Đặt tên là a và b
chung lớn nhất của 02 số đó.
• Đầu vào: Không có
• Đầu ra: Không có
• Đầu ra: Không có
void xuat_so_lon(int a, int b){
int m; void nhap_xuat_so_lon(){
if (a > b) m = a; int m, n;
else m = b; cout << "Nhap so nguyen duong"; cin >> m;
} cout << "Nhap so nguyen duong"; cin >> n;
cout << “so lon nhat giua " cout << “So lon hon trong "
<< a << " va " << b << " la " << m; << m << " va " << n << " la ";
} if (n > m) m = n;
cout << m;
}
28
29
5
9/24/2018
32
6
9/24/2018
3. Mảng 3. Mảng
• Biểu diễn một dãy các phần tử có cùng kiểu và mỗi phần tử trong • Mảng 1 chiều gồm 1 dãy các phần tử có cùng kiểu dữ liệu (int, float,
mảng biểu diễn 1 giá trị. char …) 5 8 2 7 1 0 9
• Kích thước mảng được xác định ngay khi khai báo và không thay T B R K
đổi.
• Một kiểu dữ liệu có cấu trúc do người lập trình định nghĩa. • Mảng 2 chiều (Ma trận) gồm các phần tử trên dòng và các phần tử
• Ngôn ngữ lập trình C/C++ luôn chỉ định một khối nhớ liên tục cho trên cột 3 7
một biến kiểu mảng. 3 7 3 7 8 6 1
0 1 2 3 4 5 6 7 8 9 Ma trận dòng = cột = 2 Ma trận dòng < cột Ma trận dòng > cột
Dòng = 2 , cột =3 Dòng = 3 , cột =2
A B C D E F G
39 40
7
9/24/2018
• Khởi tạo giá trị cho mọi phần tử của mảng • Chỉ số mảng (vị trí trong mảng) là một giá trị số nguyên int.
0 1 2 3
int A[4] = {29, 137, 50, 4}; • Chỉ số bắt đầu là 0 và không vượt quá số lượng phần tử tối đa
29 137 50 4
trong mảng.
• Khởi tạo giá trị cho một số phần tử đầu mảng
• Số lượng các chỉ số mảng = số lượng phần tử tối đa trong mảng
int B[4] = {91, 106}; 0 1 2 3
91 106
• Khởi tạo giá trị 0 cho mọi phần tử của mảng 0 1 2 3 4
int A[5]; 99 17 50 43 72
int a[4] = {0}; 0 1 2 3
0 0 0 0 Tên mảng: A
• Tự động xác định số lượng phần tử Kiểu dữ liệu của từng phần tử trong mảng: int
int a[] = {22, 16, 56, 19}; Số phần tử tối đa trong mảng: 5 phần tử
0 1 2 3 Các chỉ số được đánh số: 0 4 (0, 1, 2, 3, 4)
22 16 56 19
43 44
45 46
8
9/24/2018
• Ví dụ • Ví dụ
typedef struct struct DIEM
{ {
int x; int x;
int y; int y;
} DIEM; } diem1 = {2912, 1706}, diem2;
struct DIEM diem1, diem2;
9
9/24/2018
Truy xuất dữ liệu kiểu cấu trúc Gán dữ liệu kiểu cấu trúc
• Đặc điểm • Có 2 cách
• Không thể truy xuất trực tiếp <biến cấu trúc đích> = <biến cấu trúc nguồn>;
• Thông qua toán tử thành phần cấu trúc . hay còn gọi là toán tử chấm
<biến cấu trúc đích>.<tên thành phần> = <giá trị>;
(dot operation)
• Ví dụ
<tên biến cấu trúc>.<tên thành phần>
• Ví dụ struct DIEM
{
int x, y;
struct DIEM } diem1 = {2912, 1706}, diem2;
{ …
int x; diem2 = diem1;
int y; diem2.x = diem1.x;
} diem1; diem2.y = diem1.y * 2;
printf(“x = %d, y = %d”, diem1.x, diem1.y);
10
9/24/2018
• Khai báo <kiểu dữ liệu> *<tên biến con trỏ>; Khai báo:
DataType * PointerVariable;
• Giống như mọi biến khác, biến con trỏ muốn sử dụng cũng cần phải được
khai báo. Cấp phát:
Memory Layout PointerVariable = new DataType;
• Ví dụ
0x50
Hủy bộ nhớ:
char char1;
char1 0x80 delete PointerVariable ;
int *ptrI; ptrI
float *ptrF; 0x10
ptrF
61 62
Gán “giá trị trỏ bởi p1” cho “giá trị trỏ bởi p2”
63 64
0x34 int n;
• Ví dụ:
a 0x90
int a; int *p1 = &n;
int *ptr = &a; ptr 0x34
int *p2; // unreferenced local variable
Memory Layout
int *p3 = NULL;
? double a;
int *ptr = &a;
NULL
65 66
11
9/24/2018
• Toán tử * đặt trước biến con trỏ cho phép truy xuất đến giá trị ô • Con trỏ là khái niệm quan trọng và khó nhất
nhớ mà con trỏ trỏ đến. trong C++. Mức độ thành thạo C++ được đánh
• Ví dụ
giá qua mức độ sử dụng con trỏ.
int a = 1000;
0x34 • Nắm rõ quy tắc sau, ví dụ int a, int *pa = &a;
a 3201
3200
1000 • *pa và a đều chỉ nội dung của biến a.
int *ptr = &a;
cout << ptr << “ ” << *ptr; • pa và &a đều chỉ địa chỉ của biến a.
// a = 3200 0x90 • Không nên sử dụng con trỏ khi chưa được khởi
*ptr = 3200; ptr 0x34 tạo. Kết quả sẽ không lường trước được.
cout << *ptr;
int *pa; *pa = 1904; => sai
(*ptr) ++; Memory Layout
67 68
5. Con trỏ và cấp phát động 5. Con trỏ và cấp phát động
• Cú pháp khởi tạo giá trị con trỏ: <type> pointer = new <type>
(value)
• Vì con trỏ có thể tham chiếu tới biến nhưng không thực sự cần
• Ví dụ:
phải có định danh cho biến đó.
#include <iostream>
• Có thể cấp phát động cho biến con trỏ bằng toán tử new. Toán tử new
using namespace std;
sẽ tạo ra biến “không tên” cho con trỏ trỏ tới.
p1 6. p1 = new int; • Ghi chú: Sau khi gọi toán tử delete thì con trỏ vẫn trỏ tới vùng nhớ trước khi gọi hàm delete. Ta
p2 ? ? p1 ? gọi là “con trỏ lạc”. Ta vẫn có thể gọi tham chiếu trên con trỏ, tuy nhiên:
p1 7. *p1 = 50; Hãy tránh con trỏ lạc bằng cách gán con trỏ bằng NULL sau khi delete.
p2 ? 30 p1 50 • Ví dụ:
4. p2 = p1; p2 40
delete pointer;
p1 pointer = NULL;
p2 30
71 72
12
9/24/2018
73 74
5. Con trỏ và cấp phát động 5. Con trỏ và cấp phát động
• Ví dụ:
• Hạn chế của mảng chuẩn
int a[10];
• Bắt buộc phải biết trước cần bao nhiều bộ nhớ lưu trữ => tốn bộ nhớ, không
typedef int* IntPtr;
thay đổi được kích thước, …
IntPtr p;
a và p là các biến con trỏ. Dùng Mảng động
• Phép gán hợp lệ p = a;
• p bây giờ sẽ trỏ tới nơi a trỏ, tức là tới phần tử đầu tiên của mảng a
• Mảng động
• Phép gán không hợp lệ a = p; • Kích thước không xác định ở thời điểm lập trình
• Bởi con trỏ mảng là con trỏ hằng. • Mà xác định khi chạy chương trình
75 76
• Cấp phát động cho biến con trỏ • Dùng toán tử delete[] để xóa mảng động.
• Sau đó dùng con trỏ như mảng chuẩn Ví dụ:
• Cú pháp: double *d = new double[10];
<type> <pointer> = new <type> [<number_of_elements>]
Ví dụ:
//... Processing
typedef double * doublePtr; delete[] d;
Giải phóng tất cả vùng nhớ của mảng động này
doublePtr d;
Cặp ngoặc vuông báo hiệu có mảng
d = new double[10];
Nhắc lại: d vẫn trỏ tới vùng nhớ đó. Vì vậy sau khi delete, cần
Tạo biến mảng cấp phát động d có 10 phần tử, gán d = NULL;
kiểu cơ sở là double.
13
9/24/2018
• Ta không được phép trả về kiểu mảng trong hàm. • Hãy viết HÀM tạo mảng 1 chiều có n phần tử bằng cấp phát động.
Ví dụ:
int[] someFunction(); // Không hợp lệ! • Viết hàm xuất mảng 1 chiều đã tạo.
• Có thể thay bằng trả về con trỏ tới mảng có cùng kiểu cơ sở: • Viết hàm đếm số phần tử âm trong mảng 1 chiều.
int* someFunction(); // Hợp lệ!
81 82
83 84
14
9/24/2018
q = new PhanSo();
q->TuSo = 1; // giống (*q).TuSo=1
q->MauSo = 2;// giống (*q).MauSo=2
89
15
9/24/2018
Bài tập
92
16