Ngôn ngữ lập trình C/C++ Viện điện tử viễn thông-Đại Học Bách Khoa Hà Nội
Trang 1Vũ Song Tùng
Trang 2Đặc điểm của C/C++
Các thành phần cơ bản
Biểu thức và toán tử
Hàm, mảng và con trỏ
Kiểu dữ liệu trừu tượng
Các cấu trúc dữ liệu cơ bản
Trang 3• Ngôn ngữ lập trình hàm
• Linh hoạt trong việc sử dụng các kiểu biến
• Truy cập trực tiếp bộ nhớ thông qua các con trỏ
• Định nghĩa các kiểu biến mới bằng các
struct
• Có thể chia nhỏ chương trình thành nhiều mô-đun
Trang 4• Kế thừa các đặc điểm của C
• Đa hình bằng kỹ thuật xếp chồng (overload)
• Hướng đối tượng bằng các lớp (class)
• Sử dụng lại các mã bằng kỹ thuật kế thừa
(inheritance)
Trang 7• Dùng để mô tả một hàm hay một đoạn
Trang 8v.v…
• Các quy tắc định danh
– Chỉ được dùng các chữ cái, chữ số hoặc dấu gạch nối
– Ký tự đầu tiên không là chữ số
– Không được phép trùng từ khóa
Chú ý Ngôn ngữ C/C++ phân biệt chữ cái hoa và chữ cái thường
Ví dụ
void _foo() // đúng quy cách
{
int so nguyen; // sai vì có chứa dấu cách
int soNguyen; // đúng quy cách
}
Trang 9• Có thể là số nguyên, số thực, ký tự hoặc xâu ký
tự
Ví dụ
5 // số nguyên kiểu int
05 // số nguyên biểu diễn trong hệ 8
0x5 // số nguyên biểu diễn trong hệ 16
5u // U hoặc u – số nguyên kiểu unsigned
5l // L hoặc l – số nguyên kiểu long
5.0 // số nguyên kiểu double
'5' // ký tự có giá trị số (mã ASCII) bằng 53
'A' // ký tự có giá trị số (mã ASCII) bằng 65
"5" // xâu ký tự gồm ký tự '5' và ký tự NULL
Trang 11• Là một vùng trong bộ nhớ RAM dùng để lưu trữ tạm thời các giá trị được xác định bằng một tên biến
• Phân loại
• Biến đơn
• Biến mảng
• Biến con trỏ
Trang 12• Cần khai báo biến trước khi sử dụng
Ví dụ
int a, b = 1; // Khai báo biến đơn
int *pa = &a; // Khai báo biến con trỏ
Cú pháp kiểu tên_biến;
kiểu tên_biến = biểu_thức_khởi_tạo;
Trang 14int y; error C2086: 'int y' : redefinition
Trong một khối ,…-, các tên biến phải khác nhau
Cùng một tên biến có thể khai báo trong các khối ,…-
khác nhau
Trang 16• Kiểu liệt kê
• Dùng để định danh cho các giá trị kiểu int
enum tên_kiểu { danh sách tên };
Trang 17làm việc với màn hình và bàn phím
– Chuẩn vào (cin) sử dụng toán tử luồng vào (>>)
– Các chuẩn ra (cout, cerr) sử dụng toán tử luồng ra (<<)
Trang 19PhuongTrinhBac2.cpp
#include <iostream> // thư viện vào/ra
using namespace std; // nơi khai báo các thành phần chuẩn
cerr << "He so a phai khac 0.";
cout << endl; // in ký tự xuống dòng
system("pause"); // tạm dừng màn hình
}
Trang 21• Tạo project PhuongTrinhBac2 trên Visual
Studio NET và kiểm tra với các hệ số:
– a = 1, b = 2, c = 1
– a = 1, b = 2, c = 3
– a = 1, b = 3, c = 2
• Tối ưu đoạn mã giải phương trình bậc 2
Gợi ý Giảm số lượng các biểu thức 2 * a và sqrt(d)
Trang 22Biểu thức
Các toán tử đơn
Các toán tử có cấu trúc
Trang 24Bảng 3.1 Phân loại các toán tử đơn
Logic && || ! Cho giá trị 0 hoặc 1
Xử lý bit & | ~ ^ << >> Có thể kết hợp với =
Con trỏ & * new delete
Truy cập thành viên :: ->
Các loại khác {} () [] ,
Thứ tự ưu tiên các toán tử tham khảo tại
Trang 27Ví dụ
• Các toán tử tăng/giảm
++a; // tương đương: a = a + 1;
a++; // tương đương: a = a + 1;
a = b++; // tương đương: a = b; b = b + 1;
a = ++b; // tương đương: b = b + 1; a = b;
++ Tăng 1
Giảm 1
Trang 28> Lớn hơn >= Lớn hơn hoặc bằng
< Nhỏ hơn <= Nhỏ hơn hoặc bằng
Trang 29• Toán tử kiểm tra:
Biểu thức logic? Biểu thức 1: Biểu thức 2
Ví dụ
5 == 3? 5: 3 // cho giá trị 3
5 != 3? 5: 3 // cho giá trị 5
a > b? a: b // cho giá trị lớn nhất của a và b
a < 0? –a: a // cho giá trị tuyệt đối của a
Trang 30• Các toán tử logic
Ví dụ
!(a == b) // tương đương: a != b
x >= a && x <= b // kiểm tra x trong khoảng [a, b]
x < a || x > b // kiểm tra x ngoài khoảng [a, b]
&& Và
|| Hoặc
! Phủ định
Trang 31• Các toán tử logic
– Các giá trị khác 0 được coi là 1
– Trong biểu thức A && B, nếu A = 0 thì không cần xác định B
– Trong biểu thức A || B, nếu A = 1 thì không cần xác định B
x >= a && x <= b // kiểm tra x trong khoảng [a, b]
x < a || x > b // kiểm tra x ngoài khoảng [a, b]
Ví dụ
Trang 33Bảng 3.2 Một vài phương án sử dụng
• Các toán tử xử lý bit
Biểu thức Mô tả
a &= 0xFE Xóa bit a0 (a thuộc kiểu 1 byte)
(a & (1 << n)) Kiểm tra bit an
(a & 1) == 0 Kiểm tra tính chia hết cho 2 của a
Trang 34• Toán tử dấu phảy:
Dùng để phân biệt hai hay nhiều biểu thức
void _foo(int x, int y) // các tham số của hàm
{
int A[] = { 1, 2, 3, 4 };// các biểu thức khởi tạo mảng
int a, b; // các biểu thức khai báo biến
a = (b = 3, b + 2); // tương đương: b = 3; a = b+2;
_foo(a, b); // các biểu thức truyền cho hàm
}
Trang 35• Toán tử điều kiện: if …
Trang 36• Toán tử điều kiện: if … else …
else min = b;
Ví dụ
Trang 37int r = a % b;
a = b;
b = r;
} uscln = a;
Ví dụ
Trang 40• Toán tử lựa chọn: switch …
{ case giá_trị_1: các biểu thức #1 break ;
#k – khi (biểu thức) có giá trị = giá_trị_k
#khác – khi giá trị của (biểu thức) khác các giá trị đã liệt kê
Trang 41• Toán tử lựa chọn: switch …
// tìm số ngày của tháng month trong năm year
switch (month) {
case 2:
days = (year % 4) == 0? 29: 28;
break ; case 4: case 6:
case 9: case 11:
days = 30;
break ; default : days = 31;
}
Trang 42• Toán tử điều khiển: break và continue
• break – đưa con trỏ chương trình ra khỏi các vòng lặp và khối
switch
• continue – đưa con trỏ chương trình về đầu các vòng lặp
// tìm tổng các giá trị chẵn và lẻ // của các số nguyên dương nhập vào từ bàn phím
int odd = 0, even = 0, input;
odd += input;
Ví dụ
Trang 43trận mxn với k = mxn, m và n được khởi tạo trong hàm main()
• Viết chương trình xác định dạng tam giác được cho bởi 3 cạnh a, b, c là các số thực Yêu cầu:
– Nhập 3 cạnh của tam giác
– In ra màn hình kiểu của tam giác:
• Tam giac thuong
• Tam giac vuong
• Tam giac can
• Tam giac vuong can
• Tam giac deu – Chương trình chỉ kết thúc khi a, b, c không tạo thành tam giác
Trang 45Mảng
Con trỏ và tham chiếu
Hàm
Trang 46• Khai báo biến mảng
kiểu tên_biến[kích thước];
// kích thước phải là hằng số nguyên
kiểu tên_biến[kích thước] = { danh sách biểu thức }; // số biểu thức trong danh sách biểu thức phải nhỏ // hơn hoặc bằng kích thước
kiểu tên_biến[] = { danh sách biểu thức };
// kích thước của mảng bằng số biểu thức trong
// danh sách biểu thức
Trang 47• Khai báo biến mảng
Trang 48• Xâu ký tự (string)
• Mảng các ký tự, kết thúc bằng ký tự NULL
• Biến xâu ký tự được khai báo bằng một mảng kiểu char
(biểu thức khởi tạo có thể là một hằng xâu ký tự)
Ví dụ
// nhập và kiểm tra mật khẩu
char pwd[] = "12345678" ;
char s[100];
cout << "Nhap mat khau: " ; cin.getline(s, 100);
for ( int i = 0; s[i] != 0 || pwd[i] != 0; i++)
{
if (s[i] != pwd[i])
// khối biểu thức xử lý sai mật khẩu
Trang 49– Khai báo một mảng chứa 1000 số nguyên
– Đặt giá trị ngẫu nhiên từ 1 1000 cho các phần tử của mảng (dùng hàm rand())
– Đếm số lượng số chẵn, số lẻ và số chia hết cho 8 của mảng
• Viết chương trình thực hiện các thao tác sau:
– Nhập giá trị cho xâu ký tự s (chứa được nhiều nhất 49 ký tự khác NULL) – In s ra màn hình với các chữ cái thường (VD s = “123ABC” 123abc)
– Đổi s thành số nguyên và gán cho biến a (VD s = “123abc” a = 123)
Trang 50Truy cập nội dung con trỏ *tên_biến_con_trỏ
Lấy địa chỉ &tên_biến
Kiểu tham chiếu kiểu &
Bảng 4.1 Các toán tử của con trỏ và tham chiếu
Trang 51• Các khái niệm
Ví dụ
int a; // giả sử a nằm ở địa chỉ 0x000000A0
int b; // giả sử b nằm ở địa chỉ 0x000000B0
int *p = &a; // p trỏ vào a -> p = 0x000000A0
int &r = a; // r là tham chiếu của a
r = 10; // -> a = 10
b = *p; // p đang trỏ vào a -> b = 10
p = &b; // p trỏ vào b -> p = 0x000000B0
*p = 5; // -> b = 5
Trang 52• Con trỏ và mảng
• Có thể coi biến mảng như một con trỏ trỏ vào phần
tử đầu tiên của mảng
• Nếu A là một biến mảng thì (A + i) chính là địa chỉ của A[i]
Ví dụ
double A[10], *p = A;
// 3 đoạn mã tương đương
for (int i = 0; i < 10; i++) *(A + i) = 0; // A[i] = 0;
for (int i = 0; i < 10; i++) *(p + i) = 0;
for (int i = 0; i < 10; i++, p++) *p = 0;
Trang 55– Khai báo một mảng chứa n số nguyên với n được nhập từ bàn phím
– Đặt giá trị ngẫu nhiên từ 1 1000 cho các phần tử của mảng (dùng hàm rand())
– Đếm số lượng số chẵn, số lẻ và số chia hết cho 8 của mảng
• Debug đoạn biểu thức sau:
char s[100] = "1234567890" ; short *p = ( short *)s;
*(p += 2) = 0x41; cout << s;
• Viết chương trình thực hiện các thao tác sau:
– Nhập giá trị cho xâu ký tự s (chứa được nhiều nhất 49 ký tự khác NULL)
– In s ra màn hình với các chữ cái thường (VD s = “123ABC” 123abc)
– Đổi s thành số nguyên và gán cho biến s (VD s = “123abc” a = 123)
Yêu cầu: Duyệt các ký tự của s bằng con trỏ
Trang 56int factorial( int n) { }
double power( double x, int n) { }
void main() { }
Trang 57• prototype của hàm
kiểu tên_hàm(danh sách kiểu);
Vi dụ
int factorial( int );
double power( double , int );
Trang 58Bảng 4.2 Quy tắc tham số
Tham số Khai báo
Tham chiếu kiểu & tên
Chú ý:
• Dùng tham số con trỏ thay cho mảng trong prototype của hàm
• VD int sum(int *, int);
• Có thể dùng từ khóa const để cấm thay đổi giá trị các tham số trong hàm
• VD int max(const int, const int);
Trang 59• Được đặt sẵn giá trị
• Khai báo ở cuối danh sách tham số
• Chỉ cần truyền đối số khi giá trị của đối số khác giá trị mặc định
Trang 60// các biểu thức
if (a == 0) return ; // các biểu thức
Trang 61• Toán tử return
return (biểu thức);
// thoát khỏi hàm
// dùng cho các hàm khác kiểu void
// trả về cho hàm giá trị của biểu thức
Trang 62int f = Factorial(5);
double p = power(2.5, 3);
}
Trang 63Bảng 4.2 Quy tắc truyền đối số
Đối số / Tham số Tham trị Mảng Con trỏ Tham
chiếu
Trang 64• Quy tắc truyền đối số
Trang 65• Quy tắc truyền đối số
void change1(int a) { a++; }
void change2(int *p) { (*p)++; }
void change3(int &r) { r++; }
void change4(const int &r) { r++; } // báo lỗi
Trang 66// prototype của foo và goo
extern void goo( int , int );
// 1.cpp
// prototype của foo và goo
extern void goo( int , int );
Trang 67• Các mô hình định nghĩa hàm
// 1.cpp
// prototype của foo và goo
void foo( int );
void goo( int , int );
void foo( int a)
// prototype của foo và goo
extern void goo( int , int );
// 3.cpp
// prototype của foo và goo
extern void goo( int , int );
Trang 68// 1.h
#pragma once void foo( int );
void goo( int , int );
Trang 70int goo(int a) { return a * a; }
int get(int x, int (*f)(int)) { return f(x); }
void main()
{
cout << get(5, &foo) << ' ' << get(4, &goo);
Trang 72• Các hàm xếp chồng (overload)
• Các hàm cùng tên
• Phân biệt bằng kiểu hoặc danh sách tham số
double power( double x) {
double power( double x, double y) {
return exp(y * log(x));
}
Ví dụ
Trang 73• Các hàm xếp chồng (overload)
• Chương trình dịch sẽ tự gọi hàm phù hợp dựa vào
các đối số truyền cho hàm
double a;
a = power(2); // gọi hàm: double power(double)
a = power(2, 3); // gọi hàm: double power(double, int)
a = power(2, 3.0); // gọi hàm: double power(double, double)
Trang 74cout << abs(-1) // hàm sinh: int abs(int x) { }
<< abs(2.0); // hàm sinh: double abs(double x) { }
Trang 75• Thiết kế và cài đặt hàm trả về xâu ký tự theo chuẩn họ tên từ xâu đầu vào
V u H a i M i n h \0
Trang 76𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 IsSorted 𝑎 ∶ 𝐀𝐫𝐫𝐚𝐲 1 𝑛 𝐨𝐟 ℕ; 𝑡 ∶ *0, 1+ ∶ 0, 1 𝐟𝐨𝐫 𝑖 ≔ 1 𝐭𝐨 𝑛 − 1 𝐝𝐨
𝐢𝐟 𝑡 = 1 ∧ 𝑎 𝑖 > 𝑎 𝑖 + 1 𝐭𝐡𝐞𝐧 𝐫𝐞𝐭𝐮𝐫𝐧 0
𝐢𝐟 𝑡 = 0 ∧ 𝑎 𝑖 < 𝑎 𝑖 + 1 𝐭𝐡𝐞𝐧 𝐫𝐞𝐭𝐮𝐫𝐧 0 𝐫𝐞𝐭𝐮𝐫𝐧 1
• Cài đặt các hàm sắp xếp và tìm kiếm
• Viết chương trình so sánh các thuật toán sắp xếp với các mảng 100,
1000, 10000 và 100000 phần tử
Trang 77Các khái niệm
Xây dựng ADT
Các toán tử
Kế thừa
Trang 78• Kiểu dữ liệu trừu tượng (ADT) – kiểu được định nghĩa để mô tả cho một sự vật
• Đối tượng – một biến thuộc một ADT
Trang 79• Ví dụ:
• Một hình chữ nhật (Rectangle) được xác định bởi:
– tọa độ góc trên bên trái: x1, y1 – tọa độ góc dưới bên phải: x2, y2 – tính diện tích: Area = (y2 – y1) * (x2 – x1)
• Một hình ô van (Elipse) nội tiếp trong hình chữ nhật:
– tính diện tích: Area = Rectagle::Area * / 4
Trang 83• Các vùng truy cập
protected
Trang 84• Cấu trúc của ADT
class tên_ADT {
private|protected|public :
// các biến thành viên (các thuộc tính)
private|protected|public :
Trang 85• Cấu trúc của ADT
• Các hàm đơn giản (không chứa các vòng lặp hoặc rất ngắn) có thể định nghĩa inline
class tên_ADT {
{ // các biểu thức }
};
Trang 86• Cấu trúc của ADT
• Các hàm phức tạp nên định nghĩa ngoài khối khai báo ADT
class tên_ADT {
kiểu tên_hàm(danh sách tham số);
};
kiểu tên_ADT::tên_hàm(danh sách tham số) {
// các biểu thức }
Trang 88};
Trang 89• Định nghĩa hàm tạo (inline)
Trang 90Time(long value) : ticks(value) { }
Time(const Time & t) : ticks(t.ticks) { }
~Time() { }
public:
long Seconds() { return ticks / 1000; }
long Minutes() { return Seconds() / 60; }
long Hours() { return Seconds() / 3600; }
};
Trang 91• Ví dụ (class Time)
void main()
{
Time *p;
Time t1; // gọi Time()
Time t2(1000); // gọi Time(long)
Time t3 = t2; // gọi Time(const Time &)
p = new Time(100); // gọi Time(long)
cout << t2.Seconds() << endl;
cout << p->Seconds() << endl;
delete p; // gọi ~Time() của *p
} // gọi ~Time() của t3, t2 và t1
Trang 92// Lấy độ dài xâu src
static int GetLength(const char * src);
// copy xâu src vào dst
static void Copy(char * dst, const char * src);
Trang 93• Ví dụ (class String)
– Các hàm private
private :
// Hàm tạo đối lượng chứa được n ký tự
String( int n) { createData(n); }
// copy xâu src vào data
void copyData( const char * src) { Copy(data, src); }
// Tạo vùng dữ liệu chứa n ký tự
void createData( int n)
Trang 95• Ví dụ (class String)
– Các hàm public
public:
// Lấy số ký tự
int Length() { return len; }
// So sánh với đối tượng src
int Compare(const String & src) const
Trang 96• Ví dụ (class String)
– Các toán tử
public:
String operator=(const char * src);
String operator=(String & src);
// Các toán tử khác
}; // class String
Trang 99delete[] s2.data delete[] s1.data sinh ra lỗi vì s1.data đã bị xóa
Trang 100• Toán tử gán
// Bổ sung toán tử gán cho String
String& operator=(const String & right)
{
delete [] data; // xóa vùng dữ liệu cũ
createData(right.len); // tạo vùng dữ liệu mới
copyData(right.data); // copy dữ liệu từ src
return *this; // trả về bản thân đối tượng
}
Trang 101• Các toán tử số học
// Bổ sung toán tử số học cho Time
Time operator +( const Time right)
{
return Time(ticks + right.ticks);
}
// Bổ sung toán tử số học cho String
String operator +( const String & right)
Trang 102• Các toán tử kết hợp
// Bổ sung toán tử kết hợp cho Time
Time & operator +=( const Time right) {
ticks += right.ticks;
return * this ;
}
// Bổ sung toán tử kết hợp cho String
String operator +=( const String & right) {
String s(len + right.len);
Trang 103• Các toán tử so sánh
// Bổ sung toán tử so sánh cho Time
int operator==(const Time right) const
{
return (ticks == right.ticks);
}
// Bổ sung toán tử so sánh cho String
int operator==(const String & right) const
{
return (Compare(right.data) == 0);
}